Skip to content

Commit 2e5d4a8

Browse files
haimdreyfussegrumbach
authored andcommitted
iwlwifi: pcie: Add new configuration to enable MSIX
Working with MSIX requires prior configuration. This includes requesting interrupt vectors from the OS, registering the vectors and mapping the optional causes to the relevant interrupt. In addition add new interrupt handler to handle MSIX interrupt. Signed-off-by: Haim Dreyfuss <[email protected]> Signed-off-by: Emmanuel Grumbach <[email protected]>
1 parent bac842d commit 2e5d4a8

File tree

5 files changed

+507
-50
lines changed

5 files changed

+507
-50
lines changed

drivers/net/wireless/intel/iwlwifi/iwl-csr.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*
88
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
99
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
10+
* Copyright(c) 2016 Intel Deutschland GmbH
1011
*
1112
* This program is free software; you can redistribute it and/or modify
1213
* it under the terms of version 2 of the GNU General Public License as
@@ -549,4 +550,52 @@ enum dtd_diode_reg {
549550
DTS_DIODE_REG_FLAGS_PASS_ONCE = 0x00000080, /* bits [7:7] */
550551
};
551552

553+
/*****************************************************************************
554+
* MSIX related registers *
555+
*****************************************************************************/
556+
557+
#define CSR_MSIX_BASE (0x2000)
558+
#define CSR_MSIX_FH_INT_CAUSES_AD (CSR_MSIX_BASE + 0x800)
559+
#define CSR_MSIX_FH_INT_MASK_AD (CSR_MSIX_BASE + 0x804)
560+
#define CSR_MSIX_HW_INT_CAUSES_AD (CSR_MSIX_BASE + 0x808)
561+
#define CSR_MSIX_HW_INT_MASK_AD (CSR_MSIX_BASE + 0x80C)
562+
#define CSR_MSIX_AUTOMASK_ST_AD (CSR_MSIX_BASE + 0x810)
563+
#define CSR_MSIX_RX_IVAR_AD_REG (CSR_MSIX_BASE + 0x880)
564+
#define CSR_MSIX_IVAR_AD_REG (CSR_MSIX_BASE + 0x890)
565+
#define CSR_MSIX_PENDING_PBA_AD (CSR_MSIX_BASE + 0x1000)
566+
#define CSR_MSIX_RX_IVAR(cause) (CSR_MSIX_RX_IVAR_AD_REG + (cause))
567+
#define CSR_MSIX_IVAR(cause) (CSR_MSIX_IVAR_AD_REG + (cause))
568+
569+
#define MSIX_FH_INT_CAUSES_Q(q) (q)
570+
571+
/*
572+
* Causes for the FH register interrupts
573+
*/
574+
enum msix_fh_int_causes {
575+
MSIX_FH_INT_CAUSES_D2S_CH0_NUM = BIT(16),
576+
MSIX_FH_INT_CAUSES_D2S_CH1_NUM = BIT(17),
577+
MSIX_FH_INT_CAUSES_S2D = BIT(19),
578+
MSIX_FH_INT_CAUSES_FH_ERR = BIT(21),
579+
};
580+
581+
/*
582+
* Causes for the HW register interrupts
583+
*/
584+
enum msix_hw_int_causes {
585+
MSIX_HW_INT_CAUSES_REG_ALIVE = BIT(0),
586+
MSIX_HW_INT_CAUSES_REG_WAKEUP = BIT(1),
587+
MSIX_HW_INT_CAUSES_REG_CT_KILL = BIT(6),
588+
MSIX_HW_INT_CAUSES_REG_RF_KILL = BIT(7),
589+
MSIX_HW_INT_CAUSES_REG_PERIODIC = BIT(8),
590+
MSIX_HW_INT_CAUSES_REG_SW_ERR = BIT(25),
591+
MSIX_HW_INT_CAUSES_REG_SCD = BIT(26),
592+
MSIX_HW_INT_CAUSES_REG_FH_TX = BIT(27),
593+
MSIX_HW_INT_CAUSES_REG_HW_ERR = BIT(29),
594+
MSIX_HW_INT_CAUSES_REG_HAP = BIT(30),
595+
};
596+
597+
#define MSIX_MIN_INTERRUPT_VECTORS 2
598+
#define MSIX_AUTO_CLEAR_CAUSE 0
599+
#define MSIX_NON_AUTO_CLEAR_CAUSE BIT(7)
600+
552601
#endif /* !__iwl_csr_h__ */

drivers/net/wireless/intel/iwlwifi/iwl-prph.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,4 +404,6 @@ enum {
404404
LMPM_PAGE_PASS_NOTIF_POS = BIT(20),
405405
};
406406

407+
#define UREG_CHICK (0xA05C00)
408+
#define UREG_CHICK_MSIX_ENABLE BIT(25)
407409
#endif /* __iwl_prph_h__ */

drivers/net/wireless/intel/iwlwifi/pcie/internal.h

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,14 @@ struct iwl_tso_hdr_page {
336336
* @fw_mon_phys: physical address of the buffer for the firmware monitor
337337
* @fw_mon_page: points to the first page of the buffer for the firmware monitor
338338
* @fw_mon_size: size of the buffer for the firmware monitor
339+
* @msix_entries: array of MSI-X entries
340+
* @msix_enabled: true if managed to enable MSI-X
341+
* @allocated_vector: the number of interrupt vector allocated by the OS
342+
* @default_irq_num: default irq for non rx interrupt
343+
* @fh_init_mask: initial unmasked fh causes
344+
* @hw_init_mask: initial unmasked hw causes
345+
* @fh_mask: current unmasked fh causes
346+
* @hw_mask: current unmasked hw causes
339347
*/
340348
struct iwl_trans_pcie {
341349
struct iwl_rxq *rxq;
@@ -402,6 +410,15 @@ struct iwl_trans_pcie {
402410
dma_addr_t fw_mon_phys;
403411
struct page *fw_mon_page;
404412
u32 fw_mon_size;
413+
414+
struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES];
415+
bool msix_enabled;
416+
u32 allocated_vector;
417+
u32 default_irq_num;
418+
u32 fh_init_mask;
419+
u32 hw_init_mask;
420+
u32 fh_mask;
421+
u32 hw_mask;
405422
};
406423

407424
static inline struct iwl_trans_pcie *
@@ -430,7 +447,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
430447
* RX
431448
******************************************************/
432449
int iwl_pcie_rx_init(struct iwl_trans *trans);
450+
irqreturn_t iwl_pcie_msix_isr(int irq, void *data);
433451
irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id);
452+
irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id);
453+
irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id);
434454
int iwl_pcie_rx_stop(struct iwl_trans *trans);
435455
void iwl_pcie_rx_free(struct iwl_trans *trans);
436456

@@ -485,15 +505,24 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans);
485505
******************************************************/
486506
static inline void iwl_disable_interrupts(struct iwl_trans *trans)
487507
{
488-
clear_bit(STATUS_INT_ENABLED, &trans->status);
489-
490-
/* disable interrupts from uCode/NIC to host */
491-
iwl_write32(trans, CSR_INT_MASK, 0x00000000);
508+
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
492509

493-
/* acknowledge/clear/reset any interrupts still pending
494-
* from uCode or flow handler (Rx/Tx DMA) */
495-
iwl_write32(trans, CSR_INT, 0xffffffff);
496-
iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff);
510+
clear_bit(STATUS_INT_ENABLED, &trans->status);
511+
if (!trans_pcie->msix_enabled) {
512+
/* disable interrupts from uCode/NIC to host */
513+
iwl_write32(trans, CSR_INT_MASK, 0x00000000);
514+
515+
/* acknowledge/clear/reset any interrupts still pending
516+
* from uCode or flow handler (Rx/Tx DMA) */
517+
iwl_write32(trans, CSR_INT, 0xffffffff);
518+
iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff);
519+
} else {
520+
/* disable all the interrupt we might use */
521+
iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD,
522+
trans_pcie->fh_init_mask);
523+
iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD,
524+
trans_pcie->hw_init_mask);
525+
}
497526
IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
498527
}
499528

@@ -503,26 +532,69 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
503532

504533
IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
505534
set_bit(STATUS_INT_ENABLED, &trans->status);
506-
trans_pcie->inta_mask = CSR_INI_SET_MASK;
507-
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
535+
if (!trans_pcie->msix_enabled) {
536+
trans_pcie->inta_mask = CSR_INI_SET_MASK;
537+
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
538+
} else {
539+
/*
540+
* fh/hw_mask keeps all the unmasked causes.
541+
* Unlike msi, in msix cause is enabled when it is unset.
542+
*/
543+
trans_pcie->hw_mask = trans_pcie->hw_init_mask;
544+
trans_pcie->fh_mask = trans_pcie->fh_init_mask;
545+
iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD,
546+
~trans_pcie->fh_mask);
547+
iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD,
548+
~trans_pcie->hw_mask);
549+
}
550+
}
551+
552+
static inline void iwl_enable_hw_int_msk_msix(struct iwl_trans *trans, u32 msk)
553+
{
554+
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
555+
556+
iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, ~msk);
557+
trans_pcie->hw_mask = msk;
558+
}
559+
560+
static inline void iwl_enable_fh_int_msk_msix(struct iwl_trans *trans, u32 msk)
561+
{
562+
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
563+
564+
iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~msk);
565+
trans_pcie->fh_mask = msk;
508566
}
509567

510568
static inline void iwl_enable_fw_load_int(struct iwl_trans *trans)
511569
{
512570
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
513571

514572
IWL_DEBUG_ISR(trans, "Enabling FW load interrupt\n");
515-
trans_pcie->inta_mask = CSR_INT_BIT_FH_TX;
516-
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
573+
if (!trans_pcie->msix_enabled) {
574+
trans_pcie->inta_mask = CSR_INT_BIT_FH_TX;
575+
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
576+
} else {
577+
iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD,
578+
trans_pcie->hw_init_mask);
579+
iwl_enable_fh_int_msk_msix(trans,
580+
MSIX_FH_INT_CAUSES_D2S_CH0_NUM);
581+
}
517582
}
518583

519584
static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
520585
{
521586
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
522587

523588
IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
524-
trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL;
525-
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
589+
if (!trans_pcie->msix_enabled) {
590+
trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL;
591+
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
592+
} else {
593+
iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD,
594+
trans_pcie->fh_init_mask);
595+
iwl_enable_hw_int_msk_msix(trans,
596+
MSIX_HW_INT_CAUSES_REG_RF_KILL);
597+
}
526598
}
527599

528600
static inline void iwl_wake_queue(struct iwl_trans *trans,

0 commit comments

Comments
 (0)