mirror of
https://github.com/torvalds/linux.git
synced 2026-09-26 10:02:02 +02:00
mwifiex: enable pcie MSIx interrupt mode support
Newer pcie chipsets (8997 onwards) support MSIx. This patch enables it. Signed-off-by: Xinming Hu <huxm@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
68f37e5d7a
commit
99074fc1e6
|
|
@ -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) {
|
||||||
mwifiex_dbg(adapter, ERROR, "Read register failed\n");
|
pcie_ireg = BIT(msg_id);
|
||||||
return;
|
} else {
|
||||||
}
|
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
|
||||||
|
&pcie_ireg)) {
|
||||||
|
mwifiex_dbg(adapter, ERROR, "Read register failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pcie_ireg == 0xFFFFFFFF) || !pcie_ireg)
|
||||||
|
return;
|
||||||
|
|
||||||
if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
|
|
||||||
|
|
||||||
mwifiex_pcie_disable_host_int(adapter);
|
mwifiex_pcie_disable_host_int(adapter);
|
||||||
|
|
||||||
|
|
@ -2106,20 +2114,23 @@ 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);
|
}
|
||||||
adapter->int_status |= pcie_ireg;
|
|
||||||
spin_unlock_irqrestore(&adapter->int_lock, flags);
|
|
||||||
|
|
||||||
if (!adapter->pps_uapsd_mode &&
|
spin_lock_irqsave(&adapter->int_lock, flags);
|
||||||
adapter->ps_state == PS_STATE_SLEEP &&
|
adapter->int_status |= pcie_ireg;
|
||||||
mwifiex_pcie_ok_to_access_hw(adapter)) {
|
spin_unlock_irqrestore(&adapter->int_lock, flags);
|
||||||
/* Potentially for PCIe we could get other
|
mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg);
|
||||||
* interrupts like shared. Don't change power
|
|
||||||
* state until cookie is set */
|
if (!adapter->pps_uapsd_mode &&
|
||||||
adapter->ps_state = PS_STATE_AWAKE;
|
adapter->ps_state == PS_STATE_SLEEP &&
|
||||||
adapter->pm_wakeup_fw_try = false;
|
mwifiex_pcie_ok_to_access_hw(adapter)) {
|
||||||
del_timer(&adapter->wakeup_timer);
|
/* Potentially for PCIe we could get other
|
||||||
}
|
* interrupts like shared. Don't change power
|
||||||
|
* state until cookie is set
|
||||||
|
*/
|
||||||
|
adapter->ps_state = PS_STATE_AWAKE;
|
||||||
|
adapter->pm_wakeup_fw_try = false;
|
||||||
|
del_timer(&adapter->wakeup_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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) {
|
||||||
mwifiex_dbg(adapter, INFO,
|
if (card->msix_enable) {
|
||||||
"%s(): calling free_irq()\n", __func__);
|
for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
|
||||||
free_irq(card->dev->irq, card->dev);
|
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,
|
||||||
|
"%s(): calling free_irq()\n", __func__);
|
||||||
|
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 {
|
||||||
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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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 {
|
||||||
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 {
|
||||||
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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user