Commit e666aa97 authored by Alex Elder's avatar Alex Elder Committed by David S. Miller

net: ipa: support IPA interrupt addresses for IPA v4.7

Starting with IPA v4.7, registers related to IPA interrupts are
located at a fixed offset 0x1000 above than the addresses used for
earlier versions.  Define and use functions to provide the offset to
use for these registers based on IPA version.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cc5199ed
...@@ -54,12 +54,14 @@ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id) ...@@ -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); bool uc_irq = ipa_interrupt_uc(interrupt, irq_id);
struct ipa *ipa = interrupt->ipa; struct ipa *ipa = interrupt->ipa;
u32 mask = BIT(irq_id); u32 mask = BIT(irq_id);
u32 offset;
/* For microcontroller interrupts, clear the interrupt right away, /* For microcontroller interrupts, clear the interrupt right away,
* "to avoid clearing unhandled interrupts." * "to avoid clearing unhandled interrupts."
*/ */
offset = ipa_reg_irq_clr_offset(ipa->version);
if (uc_irq) 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]) if (irq_id < IPA_IRQ_COUNT && interrupt->handler[irq_id])
interrupt->handler[irq_id](interrupt->ipa, 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) ...@@ -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. * so defer clearing until after the handler has been called.
*/ */
if (!uc_irq) 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 */ /* Process all IPA interrupt types that have been signaled */
...@@ -77,13 +79,15 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt) ...@@ -77,13 +79,15 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt)
{ {
struct ipa *ipa = interrupt->ipa; struct ipa *ipa = interrupt->ipa;
u32 enabled = interrupt->enabled; u32 enabled = interrupt->enabled;
u32 offset;
u32 mask; u32 mask;
/* The status register indicates which conditions are present, /* The status register indicates which conditions are present,
* including conditions whose interrupt is not enabled. Handle * including conditions whose interrupt is not enabled. Handle
* only the enabled ones. * 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)) { while ((mask &= enabled)) {
do { do {
u32 irq_id = __ffs(mask); u32 irq_id = __ffs(mask);
...@@ -92,7 +96,7 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt) ...@@ -92,7 +96,7 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt)
ipa_interrupt_process(interrupt, irq_id); ipa_interrupt_process(interrupt, irq_id);
} while (mask); } 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) ...@@ -115,14 +119,17 @@ static irqreturn_t ipa_isr(int irq, void *dev_id)
{ {
struct ipa_interrupt *interrupt = dev_id; struct ipa_interrupt *interrupt = dev_id;
struct ipa *ipa = interrupt->ipa; struct ipa *ipa = interrupt->ipa;
u32 offset;
u32 mask; 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) if (mask & interrupt->enabled)
return IRQ_WAKE_THREAD; return IRQ_WAKE_THREAD;
/* Nothing in the mask was supposed to cause an interrupt */ /* 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", dev_err(&ipa->pdev->dev, "%s: unexpected interrupt, mask 0x%08x\n",
__func__, mask); __func__, mask);
...@@ -136,15 +143,22 @@ static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt, ...@@ -136,15 +143,22 @@ static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt,
{ {
struct ipa *ipa = interrupt->ipa; struct ipa *ipa = interrupt->ipa;
u32 mask = BIT(endpoint_id); u32 mask = BIT(endpoint_id);
u32 offset;
u32 val; u32 val;
/* assert(mask & ipa->available); */ /* 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) if (enable)
val |= mask; val |= mask;
else else
val &= ~mask; 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 */ /* Enable TX_SUSPEND for an endpoint */
...@@ -165,10 +179,18 @@ ipa_interrupt_suspend_disable(struct ipa_interrupt *interrupt, u32 endpoint_id) ...@@ -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) void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt)
{ {
struct ipa *ipa = interrupt->ipa; struct ipa *ipa = interrupt->ipa;
u32 offset;
u32 val; u32 val;
val = ioread32(ipa->reg_virt + IPA_REG_IRQ_SUSPEND_INFO_OFFSET); offset = ipa_reg_irq_suspend_info_offset(ipa->version);
iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_SUSPEND_CLR_OFFSET); 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 */ /* Simulate arrival of an IPA TX_SUSPEND interrupt */
...@@ -182,13 +204,15 @@ void ipa_interrupt_add(struct ipa_interrupt *interrupt, ...@@ -182,13 +204,15 @@ void ipa_interrupt_add(struct ipa_interrupt *interrupt,
enum ipa_irq_id ipa_irq, ipa_irq_handler_t handler) enum ipa_irq_id ipa_irq, ipa_irq_handler_t handler)
{ {
struct ipa *ipa = interrupt->ipa; struct ipa *ipa = interrupt->ipa;
u32 offset;
/* assert(ipa_irq < IPA_IRQ_COUNT); */ /* assert(ipa_irq < IPA_IRQ_COUNT); */
interrupt->handler[ipa_irq] = handler; interrupt->handler[ipa_irq] = handler;
/* Update the IPA interrupt mask to enable it */ /* Update the IPA interrupt mask to enable it */
interrupt->enabled |= BIT(ipa_irq); 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 */ /* Remove the handler for an IPA interrupt type */
...@@ -196,11 +220,13 @@ void ...@@ -196,11 +220,13 @@ void
ipa_interrupt_remove(struct ipa_interrupt *interrupt, enum ipa_irq_id ipa_irq) ipa_interrupt_remove(struct ipa_interrupt *interrupt, enum ipa_irq_id ipa_irq)
{ {
struct ipa *ipa = interrupt->ipa; struct ipa *ipa = interrupt->ipa;
u32 offset;
/* assert(ipa_irq < IPA_IRQ_COUNT); */ /* assert(ipa_irq < IPA_IRQ_COUNT); */
/* Update the IPA interrupt mask to disable it */ /* Update the IPA interrupt mask to disable it */
interrupt->enabled &= ~BIT(ipa_irq); 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; interrupt->handler[ipa_irq] = NULL;
} }
...@@ -211,6 +237,7 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa) ...@@ -211,6 +237,7 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
struct device *dev = &ipa->pdev->dev; struct device *dev = &ipa->pdev->dev;
struct ipa_interrupt *interrupt; struct ipa_interrupt *interrupt;
unsigned int irq; unsigned int irq;
u32 offset;
int ret; int ret;
ret = platform_get_irq_byname(ipa->pdev, "ipa"); ret = platform_get_irq_byname(ipa->pdev, "ipa");
...@@ -228,7 +255,8 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa) ...@@ -228,7 +255,8 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
interrupt->irq = irq; interrupt->irq = irq;
/* Start with all IPA interrupts disabled */ /* 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, ret = request_threaded_irq(irq, ipa_isr, ipa_isr_thread, IRQF_ONESHOT,
"ipa", interrupt); "ipa", interrupt);
......
...@@ -717,20 +717,46 @@ enum ipa_seq_rep_type { ...@@ -717,20 +717,46 @@ enum ipa_seq_rep_type {
#define ROUTER_HASH_MSK_METADATA_FMASK GENMASK(22, 22) #define ROUTER_HASH_MSK_METADATA_FMASK GENMASK(22, 22)
#define IPA_REG_ENDP_ROUTER_HASH_MSK_ALL GENMASK(22, 16) #define IPA_REG_ENDP_ROUTER_HASH_MSK_ALL GENMASK(22, 16)
#define IPA_REG_IRQ_STTS_OFFSET \ static inline u32 ipa_reg_irq_stts_ee_n_offset(enum ipa_version version,
IPA_REG_IRQ_STTS_EE_N_OFFSET(GSI_EE_AP) u32 ee)
#define IPA_REG_IRQ_STTS_EE_N_OFFSET(ee) \ {
(0x00003008 + 0x1000 * (ee)) if (version < IPA_VERSION_4_9)
return 0x00003008 + 0x1000 * ee;
#define IPA_REG_IRQ_EN_OFFSET \
IPA_REG_IRQ_EN_EE_N_OFFSET(GSI_EE_AP) return 0x00004008 + 0x1000 * ee;
#define IPA_REG_IRQ_EN_EE_N_OFFSET(ee) \ }
(0x0000300c + 0x1000 * (ee))
static inline u32 ipa_reg_irq_stts_offset(enum ipa_version version)
#define IPA_REG_IRQ_CLR_OFFSET \ {
IPA_REG_IRQ_CLR_EE_N_OFFSET(GSI_EE_AP) return ipa_reg_irq_stts_ee_n_offset(version, GSI_EE_AP);
#define IPA_REG_IRQ_CLR_EE_N_OFFSET(ee) \ }
(0x00003010 + 0x1000 * (ee))
static inline u32 ipa_reg_irq_en_ee_n_offset(enum ipa_version version, u32 ee)
{
if (version < IPA_VERSION_4_9)
return 0x0000300c + 0x1000 * ee;
return 0x0000400c + 0x1000 * ee;
}
static inline u32 ipa_reg_irq_en_offset(enum ipa_version version)
{
return ipa_reg_irq_en_ee_n_offset(version, GSI_EE_AP);
}
static inline u32 ipa_reg_irq_clr_ee_n_offset(enum ipa_version version, u32 ee)
{
if (version < IPA_VERSION_4_9)
return 0x00003010 + 0x1000 * ee;
return 0x00004010 + 0x1000 * ee;
}
static inline u32 ipa_reg_irq_clr_offset(enum ipa_version version)
{
return ipa_reg_irq_clr_ee_n_offset(version, GSI_EE_AP);
}
/** /**
* enum ipa_irq_id - Bit positions representing type of IPA IRQ * enum ipa_irq_id - Bit positions representing type of IPA IRQ
* @IPA_IRQ_UC_0: Microcontroller event interrupt * @IPA_IRQ_UC_0: Microcontroller event interrupt
...@@ -806,32 +832,75 @@ enum ipa_irq_id { ...@@ -806,32 +832,75 @@ enum ipa_irq_id {
IPA_IRQ_COUNT, /* Last; not an id */ IPA_IRQ_COUNT, /* Last; not an id */
}; };
#define IPA_REG_IRQ_UC_OFFSET \ static inline u32 ipa_reg_irq_uc_ee_n_offset(enum ipa_version version, u32 ee)
IPA_REG_IRQ_UC_EE_N_OFFSET(GSI_EE_AP) {
#define IPA_REG_IRQ_UC_EE_N_OFFSET(ee) \ if (version < IPA_VERSION_4_9)
(0x0000301c + 0x1000 * (ee)) return 0x0000301c + 0x1000 * ee;
return 0x0000401c + 0x1000 * ee;
}
static inline u32 ipa_reg_irq_uc_offset(enum ipa_version version)
{
return ipa_reg_irq_uc_ee_n_offset(version, GSI_EE_AP);
}
#define UC_INTR_FMASK GENMASK(0, 0) #define UC_INTR_FMASK GENMASK(0, 0)
/* ipa->available defines the valid bits in the SUSPEND_INFO register */ /* ipa->available defines the valid bits in the SUSPEND_INFO register */
#define IPA_REG_IRQ_SUSPEND_INFO_OFFSET \ static inline u32
IPA_REG_IRQ_SUSPEND_INFO_EE_N_OFFSET(GSI_EE_AP) ipa_reg_irq_suspend_info_ee_n_offset(enum ipa_version version, u32 ee)
/* This register is at (0x00003098 + 0x1000 * (ee)) for IPA v3.0 */ {
#define IPA_REG_IRQ_SUSPEND_INFO_EE_N_OFFSET(ee) \ if (version == IPA_VERSION_3_0)
(0x00003030 + 0x1000 * (ee)) return 0x00003098 + 0x1000 * ee;
/* ipa->available defines the valid bits in the IRQ_SUSPEND_EN register */ if (version < IPA_VERSION_4_9)
/* This register is present for IPA v3.1+ */ return 0x00003030 + 0x1000 * ee;
#define IPA_REG_IRQ_SUSPEND_EN_OFFSET \
IPA_REG_IRQ_SUSPEND_EN_EE_N_OFFSET(GSI_EE_AP) return 0x00004030 + 0x1000 * ee;
#define IPA_REG_IRQ_SUSPEND_EN_EE_N_OFFSET(ee) \ }
(0x00003034 + 0x1000 * (ee))
static inline u32
/* ipa->available defines the valid bits in the IRQ_SUSPEND_CLR register */ ipa_reg_irq_suspend_info_offset(enum ipa_version version)
/* This register is present for IPA v3.1+ */ {
#define IPA_REG_IRQ_SUSPEND_CLR_OFFSET \ return ipa_reg_irq_suspend_info_ee_n_offset(version, GSI_EE_AP);
IPA_REG_IRQ_SUSPEND_CLR_EE_N_OFFSET(GSI_EE_AP) }
#define IPA_REG_IRQ_SUSPEND_CLR_EE_N_OFFSET(ee) \
(0x00003038 + 0x1000 * (ee)) /* ipa->available defines the valid bits in the SUSPEND_EN register */
static inline u32
ipa_reg_irq_suspend_en_ee_n_offset(enum ipa_version version, u32 ee)
{
/* assert(version != IPA_VERSION_3_0); */
if (version < IPA_VERSION_4_9)
return 0x00003034 + 0x1000 * ee;
return 0x00004034 + 0x1000 * ee;
}
static inline u32
ipa_reg_irq_suspend_en_offset(enum ipa_version version)
{
return ipa_reg_irq_suspend_en_ee_n_offset(version, GSI_EE_AP);
}
/* ipa->available defines the valid bits in the SUSPEND_CLR register */
static inline u32
ipa_reg_irq_suspend_clr_ee_n_offset(enum ipa_version version, u32 ee)
{
/* assert(version != IPA_VERSION_3_0); */
if (version < IPA_VERSION_4_9)
return 0x00003038 + 0x1000 * ee;
return 0x00004038 + 0x1000 * ee;
}
static inline u32
ipa_reg_irq_suspend_clr_offset(enum ipa_version version)
{
return ipa_reg_irq_suspend_clr_ee_n_offset(version, GSI_EE_AP);
}
int ipa_reg_init(struct ipa *ipa); int ipa_reg_init(struct ipa *ipa);
void ipa_reg_exit(struct ipa *ipa); void ipa_reg_exit(struct ipa *ipa);
......
...@@ -192,6 +192,7 @@ void ipa_uc_teardown(struct ipa *ipa) ...@@ -192,6 +192,7 @@ void ipa_uc_teardown(struct ipa *ipa)
static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param) static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param)
{ {
struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa); struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
u32 offset;
u32 val; u32 val;
/* Fill in the command data */ /* Fill in the command data */
...@@ -203,8 +204,8 @@ static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param) ...@@ -203,8 +204,8 @@ static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param)
/* Use an interrupt to tell the microcontroller the command is ready */ /* Use an interrupt to tell the microcontroller the command is ready */
val = u32_encode_bits(1, UC_INTR_FMASK); val = u32_encode_bits(1, UC_INTR_FMASK);
offset = ipa_reg_irq_uc_offset(ipa->version);
iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_UC_OFFSET); iowrite32(val, ipa->reg_virt + offset);
} }
/* Tell the microcontroller the AP is shutting down */ /* Tell the microcontroller the AP is shutting down */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment