Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1316d595 authored by Sara Sharon's avatar Sara Sharon Committed by Luca Coelho
Browse files

iwlwifi: pcie: workaround HW shadow registers bug



Integrated 9000 devices have a bug with shadow registers
value retention.
If driver writes RBD registers while MAC is asleep the
values are stored in shadow registers to be copied whenever
MAC wakes up.
However, in 9000 devices a MAC wakeup is not triggered
and when the bus powers down due to inactivity the shadow
values and dirty bits are lost.
Turn on the chicken-bits that cause MAC wakeup for RX-related
values as well when the device is in D0.
When the device is in low power mode turn the RX wakeup chicken
bits off since driver is idle and this W/A is not needed.
Remove previous W/A which was ineffective.

Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent a6f035a0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -178,6 +178,7 @@ const struct iwl_cfg iwl5165_2ac_cfg = {
		.nvm_ver = IWL9000_NVM_VERSION,
		.nvm_calib_ver = IWL9000_TX_POWER_VERSION,
		.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
		.integrated = true,
};

MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
+3 −1
Original line number Diff line number Diff line
@@ -319,6 +319,7 @@ struct iwl_pwr_tx_backoff {
 * @mq_rx_supported: multi-queue rx support
 * @vht_mu_mimo_supported: VHT MU-MIMO support
 * @rf_id: need to read rf_id to determine the firmware image
 * @integrated: discrete or integrated
 *
 * We enable the driver to be backward compatible wrt. hardware features.
 * API differences in uCode shouldn't be handled here but through TLVs
@@ -362,7 +363,8 @@ struct iwl_cfg {
	    apmg_not_supported:1,
	    mq_rx_supported:1,
	    vht_mu_mimo_supported:1,
	    rf_id:1;
	    rf_id:1,
	    integrated:1;
	u8 valid_tx_ant;
	u8 valid_rx_ant;
	u8 non_shared_ant;
+4 −2
Original line number Diff line number Diff line
@@ -146,7 +146,9 @@
#define CSR_LED_REG             (CSR_BASE+0x094)
#define CSR_DRAM_INT_TBL_REG	(CSR_BASE+0x0A0)
#define CSR_MAC_SHADOW_REG_CTRL		(CSR_BASE + 0x0A8) /* 6000 and up */

#define CSR_MAC_SHADOW_REG_CTRL_RX_WAKE	BIT(20)
#define CSR_MAC_SHADOW_REG_CTL2		(CSR_BASE + 0x0AC)
#define CSR_MAC_SHADOW_REG_CTL2_RX_WAKE	0xFFFF

/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
+2 −0
Original line number Diff line number Diff line
@@ -673,4 +673,6 @@ static inline int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans);
int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans);

void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable);

#endif /* __iwl_trans_int_pcie_h__ */
+21 −6
Original line number Diff line number Diff line
@@ -211,11 +211,7 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
	if (trans->cfg->mq_rx_supported)
		iwl_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id),
			    rxq->write_actual);
	/*
	 * write to FH_RSCSR_CHNL0_WPTR register even in MQ as a W/A to
	 * hardware shadow registers bug - writing to RFH_Q_FRBDCB_WIDX will
	 * not wake the NIC.
	 */
	else
		iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
}

@@ -764,6 +760,23 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
		iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE);
}

void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable)
{
	/*
	 * Turn on the chicken-bits that cause MAC wakeup for RX-related
	 * values.
	 * This costs some power, but needed for W/A 9000 integrated A-step
	 * bug where shadow registers are not in the retention list and their
	 * value is lost when NIC powers down
	 */
	if (trans->cfg->integrated) {
		iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL,
			    CSR_MAC_SHADOW_REG_CTRL_RX_WAKE);
		iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2,
			    CSR_MAC_SHADOW_REG_CTL2_RX_WAKE);
	}
}

static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
{
	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -849,6 +862,8 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)

	/* Set interrupt coalescing timer to default (2048 usecs) */
	iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);

	iwl_pcie_enable_rx_wake(trans, true);
}

static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
Loading