Commit 99074fc1 authored by Xinming Hu's avatar Xinming Hu Committed by Kalle Valo

mwifiex: enable pcie MSIx interrupt mode support

Newer pcie chipsets (8997 onwards) support MSIx. This
patch enables it.
Signed-off-by: default avatarXinming Hu <huxm@marvell.com>
Signed-off-by: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 68f37e5d
...@@ -2082,20 +2082,28 @@ mwifiex_check_winner_status(struct mwifiex_adapter *adapter) ...@@ -2082,20 +2082,28 @@ mwifiex_check_winner_status(struct mwifiex_adapter *adapter)
/* /*
* This function reads the interrupt status from card. * This function reads the interrupt status from card.
*/ */
static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter,
int msg_id)
{ {
u32 pcie_ireg; u32 pcie_ireg;
unsigned long flags; unsigned long flags;
struct pcie_service_card *card = adapter->card;
if (!mwifiex_pcie_ok_to_access_hw(adapter)) if (!mwifiex_pcie_ok_to_access_hw(adapter))
return; return;
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) { if (card->msix_enable && msg_id >= 0) {
pcie_ireg = BIT(msg_id);
} else {
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
&pcie_ireg)) {
mwifiex_dbg(adapter, ERROR, "Read register failed\n"); mwifiex_dbg(adapter, ERROR, "Read register failed\n");
return; return;
} }
if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) { if ((pcie_ireg == 0xFFFFFFFF) || !pcie_ireg)
return;
mwifiex_pcie_disable_host_int(adapter); mwifiex_pcie_disable_host_int(adapter);
...@@ -2106,21 +2114,24 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) ...@@ -2106,21 +2114,24 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
"Write register failed\n"); "Write register failed\n");
return; return;
} }
}
spin_lock_irqsave(&adapter->int_lock, flags); spin_lock_irqsave(&adapter->int_lock, flags);
adapter->int_status |= pcie_ireg; adapter->int_status |= pcie_ireg;
spin_unlock_irqrestore(&adapter->int_lock, flags); spin_unlock_irqrestore(&adapter->int_lock, flags);
mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg);
if (!adapter->pps_uapsd_mode && if (!adapter->pps_uapsd_mode &&
adapter->ps_state == PS_STATE_SLEEP && adapter->ps_state == PS_STATE_SLEEP &&
mwifiex_pcie_ok_to_access_hw(adapter)) { mwifiex_pcie_ok_to_access_hw(adapter)) {
/* Potentially for PCIe we could get other /* Potentially for PCIe we could get other
* interrupts like shared. Don't change power * interrupts like shared. Don't change power
* state until cookie is set */ * state until cookie is set
*/
adapter->ps_state = PS_STATE_AWAKE; adapter->ps_state = PS_STATE_AWAKE;
adapter->pm_wakeup_fw_try = false; adapter->pm_wakeup_fw_try = false;
del_timer(&adapter->wakeup_timer); del_timer(&adapter->wakeup_timer);
} }
}
} }
/* /*
...@@ -2131,7 +2142,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) ...@@ -2131,7 +2142,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
*/ */
static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
{ {
struct pci_dev *pdev = (struct pci_dev *)context; struct mwifiex_msix_context *ctx = context;
struct pci_dev *pdev = ctx->dev;
struct pcie_service_card *card; struct pcie_service_card *card;
struct mwifiex_adapter *adapter; struct mwifiex_adapter *adapter;
...@@ -2151,7 +2163,11 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) ...@@ -2151,7 +2163,11 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
if (adapter->surprise_removed) if (adapter->surprise_removed)
goto exit; goto exit;
mwifiex_interrupt_status(adapter); if (card->msix_enable)
mwifiex_interrupt_status(adapter, ctx->msg_id);
else
mwifiex_interrupt_status(adapter, -1);
mwifiex_queue_main_work(adapter); mwifiex_queue_main_work(adapter);
exit: exit:
...@@ -2171,7 +2187,7 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) ...@@ -2171,7 +2187,7 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
* In case of Rx packets received, the packets are uploaded from card to * In case of Rx packets received, the packets are uploaded from card to
* host and processed accordingly. * host and processed accordingly.
*/ */
static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
{ {
int ret; int ret;
u32 pcie_ireg; u32 pcie_ireg;
...@@ -2251,6 +2267,69 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) ...@@ -2251,6 +2267,69 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
return 0; return 0;
} }
static int mwifiex_process_msix_int(struct mwifiex_adapter *adapter)
{
int ret;
u32 pcie_ireg;
unsigned long flags;
spin_lock_irqsave(&adapter->int_lock, flags);
/* Clear out unused interrupts */
pcie_ireg = adapter->int_status;
adapter->int_status = 0;
spin_unlock_irqrestore(&adapter->int_lock, flags);
if (pcie_ireg & HOST_INTR_DNLD_DONE) {
mwifiex_dbg(adapter, INTR,
"info: TX DNLD Done\n");
ret = mwifiex_pcie_send_data_complete(adapter);
if (ret)
return ret;
}
if (pcie_ireg & HOST_INTR_UPLD_RDY) {
mwifiex_dbg(adapter, INTR,
"info: Rx DATA\n");
ret = mwifiex_pcie_process_recv_data(adapter);
if (ret)
return ret;
}
if (pcie_ireg & HOST_INTR_EVENT_RDY) {
mwifiex_dbg(adapter, INTR,
"info: Rx EVENT\n");
ret = mwifiex_pcie_process_event_ready(adapter);
if (ret)
return ret;
}
if (pcie_ireg & HOST_INTR_CMD_DONE) {
if (adapter->cmd_sent) {
mwifiex_dbg(adapter, INTR,
"info: CMD sent Interrupt\n");
adapter->cmd_sent = false;
}
/* Handle command response */
ret = mwifiex_pcie_process_cmd_complete(adapter);
if (ret)
return ret;
}
mwifiex_dbg(adapter, INTR,
"info: cmd_sent=%d data_sent=%d\n",
adapter->cmd_sent, adapter->data_sent);
return 0;
}
static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
if (card->msix_enable)
return mwifiex_process_msix_int(adapter);
else
return mwifiex_process_pcie_int(adapter);
}
/* /*
* This function downloads data from driver to card. * This function downloads data from driver to card.
* *
...@@ -2602,10 +2681,43 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) ...@@ -2602,10 +2681,43 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
{ {
int ret; int ret, i, j;
struct pcie_service_card *card = adapter->card; struct pcie_service_card *card = adapter->card;
struct pci_dev *pdev = card->dev; struct pci_dev *pdev = card->dev;
if (card->pcie.reg->msix_support) {
for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
card->msix_entries[i].entry = i;
ret = pci_enable_msix_exact(pdev, card->msix_entries,
MWIFIEX_NUM_MSIX_VECTORS);
if (!ret) {
for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) {
card->msix_ctx[i].dev = pdev;
card->msix_ctx[i].msg_id = i;
ret = request_irq(card->msix_entries[i].vector,
mwifiex_pcie_interrupt, 0,
"MWIFIEX_PCIE_MSIX",
&card->msix_ctx[i]);
if (ret)
break;
}
if (ret) {
mwifiex_dbg(adapter, INFO, "request_irq fail: %d\n",
ret);
for (j = 0; j < i; j++)
free_irq(card->msix_entries[j].vector,
&card->msix_ctx[i]);
pci_disable_msix(pdev);
} else {
mwifiex_dbg(adapter, MSG, "MSIx enabled!");
card->msix_enable = 1;
return 0;
}
}
}
if (pci_enable_msi(pdev) != 0) if (pci_enable_msi(pdev) != 0)
pci_disable_msi(pdev); pci_disable_msi(pdev);
else else
...@@ -2613,8 +2725,10 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) ...@@ -2613,8 +2725,10 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
mwifiex_dbg(adapter, INFO, "msi_enable = %d\n", card->msi_enable); mwifiex_dbg(adapter, INFO, "msi_enable = %d\n", card->msi_enable);
card->share_irq_ctx.dev = pdev;
card->share_irq_ctx.msg_id = -1;
ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED, ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
"MRVL_PCIE", pdev); "MRVL_PCIE", &card->share_irq_ctx);
if (ret) { if (ret) {
pr_err("request_irq failed: ret=%d\n", ret); pr_err("request_irq failed: ret=%d\n", ret);
adapter->card = NULL; adapter->card = NULL;
...@@ -2660,11 +2774,28 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) ...@@ -2660,11 +2774,28 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
{ {
struct pcie_service_card *card = adapter->card; struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *reg; const struct mwifiex_pcie_card_reg *reg;
struct pci_dev *pdev = card->dev;
int i;
if (card) { if (card) {
if (card->msix_enable) {
for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
synchronize_irq(card->msix_entries[i].vector);
for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
free_irq(card->msix_entries[i].vector,
&card->msix_ctx[i]);
card->msix_enable = 0;
pci_disable_msix(pdev);
} else {
mwifiex_dbg(adapter, INFO, mwifiex_dbg(adapter, INFO,
"%s(): calling free_irq()\n", __func__); "%s(): calling free_irq()\n", __func__);
free_irq(card->dev->irq, card->dev); free_irq(card->dev->irq, &card->share_irq_ctx);
if (card->msi_enable)
pci_disable_msi(pdev);
}
reg = card->pcie.reg; reg = card->pcie.reg;
if (reg->sleep_cookie) if (reg->sleep_cookie)
......
...@@ -135,6 +135,7 @@ struct mwifiex_pcie_card_reg { ...@@ -135,6 +135,7 @@ struct mwifiex_pcie_card_reg {
u16 fw_dump_ctrl; u16 fw_dump_ctrl;
u16 fw_dump_start; u16 fw_dump_start;
u16 fw_dump_end; u16 fw_dump_end;
u8 msix_support;
}; };
static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
...@@ -166,6 +167,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { ...@@ -166,6 +167,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
.ring_tx_start_ptr = 0, .ring_tx_start_ptr = 0,
.pfu_enabled = 0, .pfu_enabled = 0,
.sleep_cookie = 1, .sleep_cookie = 1,
.msix_support = 0,
}; };
static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
...@@ -200,6 +202,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { ...@@ -200,6 +202,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
.fw_dump_ctrl = 0xcf4, .fw_dump_ctrl = 0xcf4,
.fw_dump_start = 0xcf8, .fw_dump_start = 0xcf8,
.fw_dump_end = 0xcff, .fw_dump_end = 0xcff,
.msix_support = 0,
}; };
static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
...@@ -231,6 +234,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { ...@@ -231,6 +234,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
.pfu_enabled = 1, .pfu_enabled = 1,
.sleep_cookie = 0, .sleep_cookie = 0,
.msix_support = 1,
}; };
struct mwifiex_pcie_device { struct mwifiex_pcie_device {
...@@ -290,6 +294,13 @@ struct mwifiex_pfu_buf_desc { ...@@ -290,6 +294,13 @@ struct mwifiex_pfu_buf_desc {
u32 reserved; u32 reserved;
} __packed; } __packed;
#define MWIFIEX_NUM_MSIX_VECTORS 4
struct mwifiex_msix_context {
struct pci_dev *dev;
u16 msg_id;
};
struct pcie_service_card { struct pcie_service_card {
struct pci_dev *dev; struct pci_dev *dev;
struct mwifiex_adapter *adapter; struct mwifiex_adapter *adapter;
...@@ -327,6 +338,12 @@ struct pcie_service_card { ...@@ -327,6 +338,12 @@ struct pcie_service_card {
void __iomem *pci_mmap; void __iomem *pci_mmap;
void __iomem *pci_mmap1; void __iomem *pci_mmap1;
int msi_enable; int msi_enable;
int msix_enable;
#ifdef CONFIG_PCI
struct msix_entry msix_entries[MWIFIEX_NUM_MSIX_VECTORS];
#endif
struct mwifiex_msix_context msix_ctx[MWIFIEX_NUM_MSIX_VECTORS];
struct mwifiex_msix_context share_irq_ctx;
}; };
static inline int static inline int
......
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