qcacmn: Interrupt handling support for chipset QCA8074

Changes to handle Interrupts for qca8074

Change-Id: I81d4b0722d56388cc7aca08484bd8957258621d1
Acked-by: Venkateswara Swamy Bandaru <vbandaru@codeaurora.org>
CRs-Fixed: 1042915
This commit is contained in:
Venkateswara Swamy Bandaru
2016-09-20 20:27:31 +05:30
parent 2aa2c6913e
commit 9fd9af065c
9 changed files with 211 additions and 2 deletions

View File

@@ -62,6 +62,7 @@ typedef void *hif_handle_t;
#define HIF_TYPE_QCA9984 12 #define HIF_TYPE_QCA9984 12
#define HIF_TYPE_IPQ4019 13 #define HIF_TYPE_IPQ4019 13
#define HIF_TYPE_QCA9888 14 #define HIF_TYPE_QCA9888 14
#define HIF_TYPE_QCA8074 15
/* TARGET definition needs to be abstracted in fw common /* TARGET definition needs to be abstracted in fw common
* header files, below is the placeholder till WIN codebase * header files, below is the placeholder till WIN codebase
@@ -95,6 +96,9 @@ typedef void *hif_handle_t;
/* For Adrastea target */ /* For Adrastea target */
#define TARGET_TYPE_ADRASTEA 19 #define TARGET_TYPE_ADRASTEA 19
#endif /* CONFIG_WIN */ #endif /* CONFIG_WIN */
#ifndef TARGET_TYPE_QCA8074
#define TARGET_TYPE_QCA8074 20
#endif
struct CE_state; struct CE_state;
#define CE_COUNT_MAX 12 #define CE_COUNT_MAX 12

View File

@@ -2055,6 +2055,7 @@ QDF_STATUS hif_ce_open(struct hif_softc *hif_sc)
{ {
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc);
qdf_spinlock_create(&hif_state->irq_reg_lock);
qdf_spinlock_create(&hif_state->keep_awake_lock); qdf_spinlock_create(&hif_state->keep_awake_lock);
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;
} }
@@ -2065,6 +2066,9 @@ QDF_STATUS hif_ce_open(struct hif_softc *hif_sc)
*/ */
void hif_ce_close(struct hif_softc *hif_sc) void hif_ce_close(struct hif_softc *hif_sc)
{ {
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc);
qdf_spinlock_destroy(&hif_state->irq_reg_lock);
} }
/** /**

View File

@@ -122,6 +122,7 @@ struct HIF_CE_state {
bool started; bool started;
struct ce_tasklet_entry tasklets[CE_COUNT_MAX]; struct ce_tasklet_entry tasklets[CE_COUNT_MAX];
qdf_spinlock_t keep_awake_lock; qdf_spinlock_t keep_awake_lock;
qdf_spinlock_t irq_reg_lock;
unsigned int keep_awake_count; unsigned int keep_awake_count;
bool verified_awake; bool verified_awake;
bool fake_sleep; bool fake_sleep;

View File

@@ -43,5 +43,6 @@ void hif_ahb_device_reset(struct hif_softc *scn);
int hif_ahb_enable_radio(struct hif_pci_softc *sc, int hif_ahb_enable_radio(struct hif_pci_softc *sc,
struct platform_device *pdev, struct platform_device *pdev,
const struct platform_device_id *id); const struct platform_device_id *id);
int hif_ahb_configure_irq(struct hif_pci_softc *sc);
#endif #endif

View File

@@ -680,6 +680,12 @@ int hif_get_device_type(uint32_t device_id,
HIF_INFO(" *********** IPQ4019 *************"); HIF_INFO(" *********** IPQ4019 *************");
break; break;
case QCA8074_DEVICE_ID:
*hif_type = HIF_TYPE_QCA8074;
*target_type = TARGET_TYPE_QCA8074;
HIF_INFO(" *********** QCA8074 *************\n");
break;
default: default:
HIF_ERROR("%s: Unsupported device ID!", __func__); HIF_ERROR("%s: Unsupported device ID!", __func__);
ret = -ENODEV; ret = -ENODEV;

View File

@@ -91,6 +91,10 @@
#define QCA9984_DEVICE_ID (0x0046) #define QCA9984_DEVICE_ID (0x0046)
#define QCA9888_DEVICE_ID (0x0056) #define QCA9888_DEVICE_ID (0x0056)
#define IPQ4019_DEVICE_ID (0x12ef) #define IPQ4019_DEVICE_ID (0x12ef)
#define QCA8074_DEVICE_ID (0xffff) /* Todo: replace this with
actual number once available.
currently defining this to 0xffff for
emulation purpose */
#define HIF_GET_PCI_SOFTC(scn) ((struct hif_pci_softc *)scn) #define HIF_GET_PCI_SOFTC(scn) ((struct hif_pci_softc *)scn)
#define HIF_GET_CE_STATE(scn) ((struct HIF_CE_state *)scn) #define HIF_GET_CE_STATE(scn) ((struct HIF_CE_state *)scn)
@@ -127,6 +131,7 @@ struct hif_softc {
bool recovery; bool recovery;
bool notice_send; bool notice_send;
bool per_ce_irq;
uint32_t ce_irq_summary; uint32_t ce_irq_summary;
/* No of copy engines supported */ /* No of copy engines supported */
unsigned int ce_count; unsigned int ce_count;

View File

@@ -1952,6 +1952,10 @@ int hif_pci_bus_configure(struct hif_softc *hif_sc)
} }
} }
if (hif_sc->target_info.target_type == TARGET_TYPE_QCA8074) {
hif_sc->per_ce_irq = true;
}
status = hif_config_ce(hif_sc); status = hif_config_ce(hif_sc);
if (status) if (status)
goto disable_wlan; goto disable_wlan;
@@ -3319,6 +3323,9 @@ int hif_configure_irq(struct hif_softc *scn)
case TARGET_TYPE_IPQ4019: case TARGET_TYPE_IPQ4019:
ret = hif_ahb_configure_legacy_irq(sc); ret = hif_ahb_configure_legacy_irq(sc);
break; break;
case TARGET_TYPE_QCA8074:
ret = hif_ahb_configure_irq(sc);
break;
default: default:
ret = hif_pci_configure_legacy_irq(sc); ret = hif_pci_configure_legacy_irq(sc);
break; break;

View File

@@ -103,6 +103,12 @@ void hif_target_register_tbl_attach(struct hif_softc *scn, u32 target_type)
scn->target_ce_def = IPQ4019_CE_TARGETdef; scn->target_ce_def = IPQ4019_CE_TARGETdef;
break; break;
#endif #endif
#if defined(QCA8074_HEADERS_DEF)
case TARGET_TYPE_QCA8074:
scn->targetdef = QCA8074_TARGETdef;
scn->target_ce_def = QCA8074_CE_TARGETdef;
break;
#endif
#endif #endif
default: default:
@@ -167,6 +173,11 @@ void hif_register_tbl_attach(struct hif_softc *scn, u32 hif_type)
scn->hostdef = IPQ4019_HOSTdef; scn->hostdef = IPQ4019_HOSTdef;
break; break;
#endif #endif
#if defined(QCA8074_HEADERS_DEF)
case HIF_TYPE_QCA8074:
scn->hostdef = QCA8074_HOSTdef;
break;
#endif
#endif #endif
default: default:

View File

@@ -36,6 +36,69 @@
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
#define IRQF_DISABLED 0x00000020 #define IRQF_DISABLED 0x00000020
#endif #endif
#define HIF_IC_CE0_IRQ_OFFSET 4
#define HIF_IC_MAX_IRQ 54
/* integrated chip irq names */
const char *ic_irqname[HIF_IC_MAX_IRQ] = {
"misc_pulse1",
"misc_latch",
"sw_exception",
"watchdog",
"ce0",
"ce1",
"ce2",
"ce3",
"ce4",
"ce5",
"ce6",
"ce7",
"ce8",
"ce9",
"ce10",
"ce11",
"ce12",
"ce13",
"host2wbm_desc_feed",
"host2reo_re_injection",
"host2reo_command",
"host2rxdma_monitor_ring3",
"host2rxdma_monitor_ring2",
"host2rxdma_monitor_ring1",
"reo2ost_exception",
"wbm2host_rx_release",
"reo2host_status",
"reo2host_destination_ring4",
"reo2host_destination_ring3",
"reo2host_destination_ring2",
"reo2host_destination_ring1",
"rxdma2host_monitor_destination_mac3",
"rxdma2host_monitor_destination_mac2",
"rxdma2host_monitor_destination_mac1",
"ppdu_end_interrupts_mac3",
"ppdu_end_interrupts_mac2",
"ppdu_end_interrupts_mac1",
"rxdma2host_monitor_status_ring_mac3",
"rxdma2host_monitor_status_ring_mac2",
"rxdma2host_monitor_status_ring_mac1",
"host2rxdma_host_buf_ring_mac3",
"host2rxdma_host_buf_ring_mac2",
"host2rxdma_host_buf_ring_mac1",
"rxdma2host_destination_ring_mac3",
"rxdma2host_destination_ring_mac2",
"rxdma2host_destination_ring_mac1",
"host2tcl_input_ring4",
"host2tcl_input_ring3",
"host2tcl_input_ring2",
"host2tcl_input_ring1",
"wbm2host_tx_completions_ring3",
"wbm2host_tx_completions_ring2",
"wbm2host_tx_completions_ring1",
"tcl2host_status_ring",
};
irqreturn_t hif_ahb_interrupt_handler(int irq, void *context);
/** /**
* hif_disable_isr() - disable isr * hif_disable_isr() - disable isr
* *
@@ -178,6 +241,41 @@ end:
return ret; return ret;
} }
int hif_ahb_configure_irq(struct hif_pci_softc *sc)
{
int ret = 0;
struct hif_softc *scn = HIF_GET_SOFTC(sc);
struct platform_device *pdev = (struct platform_device *)sc->pdev;
struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(scn);
int irq = 0;
int i;
/* configure per CE interrupts */
for (i = 0; i < scn->ce_count; i++) {
irq = platform_get_irq_byname(pdev, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i]);
ret = request_irq(irq ,
hif_ahb_interrupt_handler,
IRQF_TRIGGER_RISING, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i],
&hif_ce_state->tasklets[i]);
if (ret) {
dev_err(&pdev->dev, "ath_request_irq failed\n");
ret = -1;
goto end;
}
hif_ahb_irq_enable(scn, i);
}
end:
return ret;
}
irqreturn_t hif_ahb_interrupt_handler(int irq, void *context)
{
struct ce_tasklet_entry *tasklet_entry = context;
return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry);
}
/** /**
* hif_target_sync() : ensure the target is ready * hif_target_sync() : ensure the target is ready
* @scn: hif control structure * @scn: hif control structure
@@ -394,7 +492,33 @@ void hif_ahb_reset_soc(struct hif_softc *hif_ctx)
*/ */
void hif_ahb_nointrs(struct hif_softc *scn) void hif_ahb_nointrs(struct hif_softc *scn)
{ {
hif_pci_nointrs(scn); int i;
int irq;
struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
struct platform_device *pdev = (struct platform_device *)sc->pdev;
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
if (scn->request_irq_done == false)
return;
if (sc->num_msi_intrs > 0) {
/* MSI interrupt(s) */
for (i = 0; i < sc->num_msi_intrs; i++) {
free_irq(sc->irq + i, sc);
}
sc->num_msi_intrs = 0;
} else {
if (!scn->per_ce_irq) {
free_irq(sc->irq, sc);
} else {
for (i = 0; i < scn->ce_count; i++) {
irq = platform_get_irq_byname(pdev, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i]);
free_irq(irq, sc);
}
}
}
ce_unregister_irq(hif_state, CE_ALL_BITMAP);
scn->request_irq_done = false;
} }
/** /**
@@ -408,7 +532,31 @@ void hif_ahb_nointrs(struct hif_softc *scn)
*/ */
void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id) void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id)
{ {
hif_pci_irq_enable(scn, ce_id); uint32_t regval;
uint32_t reg_offset = 0;
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id];
if (scn->per_ce_irq) {
if (target_ce_conf->pipedir & PIPEDIR_OUT) {
reg_offset = HOST_IE_ADDRESS;
qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
regval = hif_read32_mb(scn->mem + reg_offset);
regval |= (1 << ce_id);
hif_write32_mb(scn->mem + reg_offset, regval);
qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
}
if (target_ce_conf->pipedir & PIPEDIR_IN) {
reg_offset = HOST_IE_ADDRESS_2;
qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
regval = hif_read32_mb(scn->mem + reg_offset);
regval |= (1 << ce_id);
hif_write32_mb(scn->mem + reg_offset, regval);
qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
}
} else {
hif_pci_irq_enable(scn, ce_id);
}
} }
/** /**
@@ -420,5 +568,27 @@ void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id)
*/ */
void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id) void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id)
{ {
uint32_t regval;
uint32_t reg_offset = 0;
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id];
if (scn->per_ce_irq) {
if (target_ce_conf->pipedir & PIPEDIR_OUT) {
reg_offset = HOST_IE_ADDRESS;
qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
regval = hif_read32_mb(scn->mem + reg_offset);
regval &= ~(1 << ce_id);
hif_write32_mb(scn->mem + reg_offset, regval);
qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
}
if (target_ce_conf->pipedir & PIPEDIR_IN) {
reg_offset = HOST_IE_ADDRESS_2;
qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
regval = hif_read32_mb(scn->mem + reg_offset);
regval &= ~(1 << ce_id);
hif_write32_mb(scn->mem + reg_offset, regval);
qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
}
}
} }