Commit b01483a8 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ipa-reg-versions'



Alex Elder says:

====================
net: ipa: update registers for other versions

This series updates IPA and GSI register definitions to permit more
versions of IPA hardware to be supported.  Most of the updates are
informational, updating comments to indicate which IPA versions
support each register and field.  But some registers are new and
others are deprecated.  In a few cases register fields are laid
out differently, and in these cases the changes are a little more
substantive.

I won't claim the result is 100% correct, but it's close, and should
allow all IPA versions 3.x through 4.x to be supported by the driver.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ae8f5867 2ad6f03b
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -701,7 +701,7 @@ static void gsi_evt_ring_program(struct gsi *gsi, u32 evt_ring_id)
	val |= u32_encode_bits(GSI_RING_ELEMENT_SIZE, EV_ELEMENT_SIZE_FMASK);
	iowrite32(val, gsi->virt + GSI_EV_CH_E_CNTXT_0_OFFSET(evt_ring_id));

	val = u32_encode_bits(size, EV_R_LENGTH_FMASK);
	val = ev_r_length_encoded(gsi->version, size);
	iowrite32(val, gsi->virt + GSI_EV_CH_E_CNTXT_1_OFFSET(evt_ring_id));

	/* The context 2 and 3 registers store the low-order and
@@ -801,14 +801,14 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell)
	channel->tre_ring.index = 0;

	/* We program all channels as GPI type/protocol */
	val = u32_encode_bits(GSI_CHANNEL_TYPE_GPI, CHTYPE_PROTOCOL_FMASK);
	val = chtype_protocol_encoded(gsi->version, GSI_CHANNEL_TYPE_GPI);
	if (channel->toward_ipa)
		val |= CHTYPE_DIR_FMASK;
	val |= u32_encode_bits(channel->evt_ring_id, ERINDEX_FMASK);
	val |= u32_encode_bits(GSI_RING_ELEMENT_SIZE, ELEMENT_SIZE_FMASK);
	iowrite32(val, gsi->virt + GSI_CH_C_CNTXT_0_OFFSET(channel_id));

	val = u32_encode_bits(size, R_LENGTH_FMASK);
	val = r_length_encoded(gsi->version, size);
	iowrite32(val, gsi->virt + GSI_CH_C_CNTXT_1_OFFSET(channel_id));

	/* The context 2 and 3 registers store the low-order and
@@ -842,6 +842,9 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell)
			val |= u32_encode_bits(GSI_ESCAPE_BUF_ONLY,
					       PREFETCH_MODE_FMASK);
	}
	/* All channels set DB_IN_BYTES */
	if (gsi->version >= IPA_VERSION_4_9)
		val |= DB_IN_BYTES;

	iowrite32(val, gsi->virt + GSI_CH_C_QOS_OFFSET(channel_id));

+55 −14
Original line number Diff line number Diff line
@@ -64,6 +64,21 @@
			(0x0000c01c + 0x1000 * (ee))

/* All other register offsets are relative to gsi->virt */

/** enum gsi_channel_type - CHTYPE_PROTOCOL field values in CH_C_CNTXT_0 */
enum gsi_channel_type {
	GSI_CHANNEL_TYPE_MHI			= 0x0,
	GSI_CHANNEL_TYPE_XHCI			= 0x1,
	GSI_CHANNEL_TYPE_GPI			= 0x2,
	GSI_CHANNEL_TYPE_XDCI			= 0x3,
	GSI_CHANNEL_TYPE_WDI2			= 0x4,
	GSI_CHANNEL_TYPE_GCI			= 0x5,
	GSI_CHANNEL_TYPE_WDI3			= 0x6,
	GSI_CHANNEL_TYPE_MHIP			= 0x7,
	GSI_CHANNEL_TYPE_AQC			= 0x8,
	GSI_CHANNEL_TYPE_11AD			= 0x9,
};

#define GSI_CH_C_CNTXT_0_OFFSET(ch) \
		GSI_EE_N_CH_C_CNTXT_0_OFFSET((ch), GSI_EE_AP)
#define GSI_EE_N_CH_C_CNTXT_0_OFFSET(ch, ee) \
@@ -78,19 +93,35 @@
#define CHSTATE_FMASK			GENMASK(23, 20)
#define ELEMENT_SIZE_FMASK		GENMASK(31, 24)

/** enum gsi_channel_type - CHTYPE_PROTOCOL field values in CH_C_CNTXT_0 */
enum gsi_channel_type {
	GSI_CHANNEL_TYPE_MHI			= 0x0,
	GSI_CHANNEL_TYPE_XHCI			= 0x1,
	GSI_CHANNEL_TYPE_GPI			= 0x2,
	GSI_CHANNEL_TYPE_XDCI			= 0x3,
};
/* Encoded value for CH_C_CNTXT_0 register channel protocol fields */
static inline u32
chtype_protocol_encoded(enum ipa_version version, enum gsi_channel_type type)
{
	u32 val;

	val = u32_encode_bits(type, CHTYPE_PROTOCOL_FMASK);
	if (version < IPA_VERSION_4_5)
		return val;

	/* Encode upper bit(s) as well */
	type >>= hweight32(CHTYPE_PROTOCOL_FMASK);
	val |= u32_encode_bits(type, CHTYPE_PROTOCOL_MSB_FMASK);

	return val;
}

#define GSI_CH_C_CNTXT_1_OFFSET(ch) \
		GSI_EE_N_CH_C_CNTXT_1_OFFSET((ch), GSI_EE_AP)
#define GSI_EE_N_CH_C_CNTXT_1_OFFSET(ch, ee) \
		(0x0001c004 + 0x4000 * (ee) + 0x80 * (ch))
#define R_LENGTH_FMASK			GENMASK(15, 0)

/* Encoded value for CH_C_CNTXT_1 register R_LENGTH field */
static inline u32 r_length_encoded(enum ipa_version version, u32 length)
{
	if (version < IPA_VERSION_4_9)
		return u32_encode_bits(length, GENMASK(15, 0));
	return u32_encode_bits(length, GENMASK(19, 0));
}

#define GSI_CH_C_CNTXT_2_OFFSET(ch) \
		GSI_EE_N_CH_C_CNTXT_2_OFFSET((ch), GSI_EE_AP)
@@ -114,6 +145,9 @@ enum gsi_channel_type {
/* The next two fields are present for IPA v4.5 and above */
#define PREFETCH_MODE_FMASK		GENMASK(13, 10)
#define EMPTY_LVL_THRSHOLD_FMASK	GENMASK(23, 16)
/* The next field is present for IPA v4.9 and above */
#define DB_IN_BYTES			GENMASK(24, 24)

/** enum gsi_prefetch_mode - PREFETCH_MODE field in CH_C_QOS */
enum gsi_prefetch_mode {
	GSI_USE_PREFETCH_BUFS			= 0x0,
@@ -146,19 +180,25 @@ enum gsi_prefetch_mode {
		GSI_EE_N_EV_CH_E_CNTXT_0_OFFSET((ev), GSI_EE_AP)
#define GSI_EE_N_EV_CH_E_CNTXT_0_OFFSET(ev, ee) \
		(0x0001d000 + 0x4000 * (ee) + 0x80 * (ev))
/* enum gsi_channel_type defines EV_CHTYPE field values in EV_CH_E_CNTXT_0 */
#define EV_CHTYPE_FMASK			GENMASK(3, 0)
#define EV_EE_FMASK			GENMASK(7, 4)
#define EV_EVCHID_FMASK			GENMASK(15, 8)
#define EV_INTYPE_FMASK			GENMASK(16, 16)
#define EV_CHSTATE_FMASK		GENMASK(23, 20)
#define EV_ELEMENT_SIZE_FMASK		GENMASK(31, 24)
/* enum gsi_channel_type defines EV_CHTYPE field values in EV_CH_E_CNTXT_0 */

#define GSI_EV_CH_E_CNTXT_1_OFFSET(ev) \
		GSI_EE_N_EV_CH_E_CNTXT_1_OFFSET((ev), GSI_EE_AP)
#define GSI_EE_N_EV_CH_E_CNTXT_1_OFFSET(ev, ee) \
		(0x0001d004 + 0x4000 * (ee) + 0x80 * (ev))
#define EV_R_LENGTH_FMASK		GENMASK(15, 0)
/* Encoded value for EV_CH_C_CNTXT_1 register EV_R_LENGTH field */
static inline u32 ev_r_length_encoded(enum ipa_version version, u32 length)
{
	if (version < IPA_VERSION_4_9)
		return u32_encode_bits(length, GENMASK(15, 0));
	return u32_encode_bits(length, GENMASK(19, 0));
}

#define GSI_EV_CH_E_CNTXT_2_OFFSET(ev) \
		GSI_EE_N_EV_CH_E_CNTXT_2_OFFSET((ev), GSI_EE_AP)
@@ -248,6 +288,7 @@ enum gsi_ch_cmd_opcode {
	GSI_CH_STOP				= 0x2,
	GSI_CH_RESET				= 0x9,
	GSI_CH_DE_ALLOC				= 0xa,
	GSI_CH_DB_STOP				= 0xb,
};

#define GSI_EV_CH_CMD_OFFSET \
@@ -278,6 +319,7 @@ enum gsi_generic_cmd_opcode {
	GSI_GENERIC_ALLOCATE_CHANNEL		= 0x2,
};

/* The next register is present for IPA v3.5.1 and above */
#define GSI_GSI_HW_PARAM_2_OFFSET \
			GSI_EE_N_GSI_HW_PARAM_2_OFFSET(GSI_EE_AP)
#define GSI_EE_N_GSI_HW_PARAM_2_OFFSET(ee) \
@@ -424,6 +466,8 @@ enum gsi_general_id {
			GSI_EE_N_ERROR_LOG_OFFSET(GSI_EE_AP)
#define GSI_EE_N_ERROR_LOG_OFFSET(ee) \
			(0x0001f200 + 0x4000 * (ee))

/* Fields below are present for IPA v3.5.1 and above */
#define ERR_ARG3_FMASK			GENMASK(3, 0)
#define ERR_ARG2_FMASK			GENMASK(7, 4)
#define ERR_ARG1_FMASK			GENMASK(11, 8)
@@ -474,7 +518,4 @@ enum gsi_generic_ee_result {
	GENERIC_EE_NO_RESOURCES			= 0x7,
};

#define USB_MAX_PACKET_FMASK		GENMASK(15, 15)	/* 0: HS; 1: SS */
#define MHI_BASE_CHANNEL_FMASK		GENMASK(31, 24)

#endif	/* _GSI_REG_H_ */
+41 −13
Original line number Diff line number Diff line
@@ -54,12 +54,14 @@ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id)
	bool uc_irq = ipa_interrupt_uc(interrupt, irq_id);
	struct ipa *ipa = interrupt->ipa;
	u32 mask = BIT(irq_id);
	u32 offset;

	/* For microcontroller interrupts, clear the interrupt right away,
	 * "to avoid clearing unhandled interrupts."
	 */
	offset = ipa_reg_irq_clr_offset(ipa->version);
	if (uc_irq)
		iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
		iowrite32(mask, ipa->reg_virt + offset);

	if (irq_id < IPA_IRQ_COUNT && interrupt->handler[irq_id])
		interrupt->handler[irq_id](interrupt->ipa, irq_id);
@@ -69,7 +71,7 @@ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id)
	 * so defer clearing until after the handler has been called.
	 */
	if (!uc_irq)
		iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
		iowrite32(mask, ipa->reg_virt + offset);
}

/* Process all IPA interrupt types that have been signaled */
@@ -77,13 +79,15 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt)
{
	struct ipa *ipa = interrupt->ipa;
	u32 enabled = interrupt->enabled;
	u32 offset;
	u32 mask;

	/* The status register indicates which conditions are present,
	 * including conditions whose interrupt is not enabled.  Handle
	 * only the enabled ones.
	 */
	mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
	offset = ipa_reg_irq_stts_offset(ipa->version);
	mask = ioread32(ipa->reg_virt + offset);
	while ((mask &= enabled)) {
		do {
			u32 irq_id = __ffs(mask);
@@ -92,7 +96,7 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt)

			ipa_interrupt_process(interrupt, irq_id);
		} while (mask);
		mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
		mask = ioread32(ipa->reg_virt + offset);
	}
}

@@ -115,14 +119,17 @@ static irqreturn_t ipa_isr(int irq, void *dev_id)
{
	struct ipa_interrupt *interrupt = dev_id;
	struct ipa *ipa = interrupt->ipa;
	u32 offset;
	u32 mask;

	mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
	offset = ipa_reg_irq_stts_offset(ipa->version);
	mask = ioread32(ipa->reg_virt + offset);
	if (mask & interrupt->enabled)
		return IRQ_WAKE_THREAD;

	/* Nothing in the mask was supposed to cause an interrupt */
	iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
	offset = ipa_reg_irq_clr_offset(ipa->version);
	iowrite32(mask, ipa->reg_virt + offset);

	dev_err(&ipa->pdev->dev, "%s: unexpected interrupt, mask 0x%08x\n",
		__func__, mask);
@@ -136,15 +143,22 @@ static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt,
{
	struct ipa *ipa = interrupt->ipa;
	u32 mask = BIT(endpoint_id);
	u32 offset;
	u32 val;

	/* assert(mask & ipa->available); */
	val = ioread32(ipa->reg_virt + IPA_REG_IRQ_SUSPEND_EN_OFFSET);

	/* IPA version 3.0 does not support TX_SUSPEND interrupt control */
	if (ipa->version == IPA_VERSION_3_0)
		return;

	offset = ipa_reg_irq_suspend_en_offset(ipa->version);
	val = ioread32(ipa->reg_virt + offset);
	if (enable)
		val |= mask;
	else
		val &= ~mask;
	iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_SUSPEND_EN_OFFSET);
	iowrite32(val, ipa->reg_virt + offset);
}

/* Enable TX_SUSPEND for an endpoint */
@@ -165,10 +179,18 @@ ipa_interrupt_suspend_disable(struct ipa_interrupt *interrupt, u32 endpoint_id)
void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt)
{
	struct ipa *ipa = interrupt->ipa;
	u32 offset;
	u32 val;

	val = ioread32(ipa->reg_virt + IPA_REG_IRQ_SUSPEND_INFO_OFFSET);
	iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_SUSPEND_CLR_OFFSET);
	offset = ipa_reg_irq_suspend_info_offset(ipa->version);
	val = ioread32(ipa->reg_virt + offset);

	/* SUSPEND interrupt status isn't cleared on IPA version 3.0 */
	if (ipa->version == IPA_VERSION_3_0)
		return;

	offset = ipa_reg_irq_suspend_clr_offset(ipa->version);
	iowrite32(val, ipa->reg_virt + offset);
}

/* Simulate arrival of an IPA TX_SUSPEND interrupt */
@@ -182,13 +204,15 @@ void ipa_interrupt_add(struct ipa_interrupt *interrupt,
		       enum ipa_irq_id ipa_irq, ipa_irq_handler_t handler)
{
	struct ipa *ipa = interrupt->ipa;
	u32 offset;

	/* assert(ipa_irq < IPA_IRQ_COUNT); */
	interrupt->handler[ipa_irq] = handler;

	/* Update the IPA interrupt mask to enable it */
	interrupt->enabled |= BIT(ipa_irq);
	iowrite32(interrupt->enabled, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
	offset = ipa_reg_irq_en_offset(ipa->version);
	iowrite32(interrupt->enabled, ipa->reg_virt + offset);
}

/* Remove the handler for an IPA interrupt type */
@@ -196,11 +220,13 @@ void
ipa_interrupt_remove(struct ipa_interrupt *interrupt, enum ipa_irq_id ipa_irq)
{
	struct ipa *ipa = interrupt->ipa;
	u32 offset;

	/* assert(ipa_irq < IPA_IRQ_COUNT); */
	/* Update the IPA interrupt mask to disable it */
	interrupt->enabled &= ~BIT(ipa_irq);
	iowrite32(interrupt->enabled, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
	offset = ipa_reg_irq_en_offset(ipa->version);
	iowrite32(interrupt->enabled, ipa->reg_virt + offset);

	interrupt->handler[ipa_irq] = NULL;
}
@@ -211,6 +237,7 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
	struct device *dev = &ipa->pdev->dev;
	struct ipa_interrupt *interrupt;
	unsigned int irq;
	u32 offset;
	int ret;

	ret = platform_get_irq_byname(ipa->pdev, "ipa");
@@ -228,7 +255,8 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
	interrupt->irq = irq;

	/* Start with all IPA interrupts disabled */
	iowrite32(0, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
	offset = ipa_reg_irq_en_offset(ipa->version);
	iowrite32(0, ipa->reg_virt + offset);

	ret = request_threaded_irq(irq, ipa_isr, ipa_isr_thread, IRQF_ONESHOT,
				   "ipa", interrupt);
+1 −1
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ static void ipa_teardown(struct ipa *ipa)
	gsi_teardown(&ipa->gsi);
}

/* Configure QMB Core Master Port selection */
/* Configure bus access behavior for IPA components */
static void ipa_hardware_config_comp(struct ipa *ipa)
{
	u32 val;
+258 −90

File changed.

Preview size limit exceeded, changes collapsed.

Loading