[iwm] Implement apmg_wake_up_wa workaround properly for 7000 family.
* Add iwm_pcie_set_cmd_in_flight() and iwm_pcie_clear_cmd_in_flight() helper methods. * Use ring->queued tracking in the command queue to set/clear the cmd_hold_nic_awake bit at the right points. Taken-From: Linux iwlwifi Obtained from: DragonflyBSD commit ce43f57f5308b579ea21e8a5a29969114ba2247d
This commit is contained in:
parent
0fae13e67a
commit
5b92aa7f37
@ -182,7 +182,8 @@ __FBSDID("$FreeBSD$");
|
||||
#define IWM_DEVICE_7000_COMMON \
|
||||
.device_family = IWM_DEVICE_FAMILY_7000, \
|
||||
.eeprom_size = IWM_OTP_LOW_IMAGE_SIZE_FAMILY_7000, \
|
||||
.nvm_hw_section_num = IWM_NVM_HW_SECTION_NUM_FAMILY_7000
|
||||
.nvm_hw_section_num = IWM_NVM_HW_SECTION_NUM_FAMILY_7000, \
|
||||
.apmg_wake_up_wa = 1
|
||||
|
||||
const struct iwm_cfg iwm7260_cfg = {
|
||||
.fw_name = IWM7260_FW,
|
||||
@ -1251,6 +1252,9 @@ iwm_reset_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring)
|
||||
sc->qfullmsk &= ~(1 << ring->qid);
|
||||
ring->queued = 0;
|
||||
ring->cur = 0;
|
||||
|
||||
if (ring->qid == IWM_MVM_CMD_QUEUE && sc->cmd_hold_nic_awake)
|
||||
iwm_pcie_clear_cmd_in_flight(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3338,6 +3342,18 @@ iwm_cmd_done(struct iwm_softc *sc, struct iwm_rx_packet *pkt)
|
||||
data->m = NULL;
|
||||
}
|
||||
wakeup(&ring->desc[pkt->hdr.idx]);
|
||||
|
||||
if (((pkt->hdr.idx + ring->queued) % IWM_TX_RING_COUNT) != ring->cur) {
|
||||
device_printf(sc->sc_dev,
|
||||
"%s: Some HCMDs skipped?: idx=%d queued=%d cur=%d\n",
|
||||
__func__, pkt->hdr.idx, ring->queued, ring->cur);
|
||||
/* XXX call iwm_force_nmi() */
|
||||
}
|
||||
|
||||
KASSERT(ring->queued > 0, ("ring->queued is empty?"));
|
||||
ring->queued--;
|
||||
if (ring->queued == 0)
|
||||
iwm_pcie_clear_cmd_in_flight(sc);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -5580,9 +5596,6 @@ iwm_notif_intr(struct iwm_softc *sc)
|
||||
ADVANCE_RXQ(sc);
|
||||
}
|
||||
|
||||
IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
|
||||
/*
|
||||
* Tell the firmware what we have processed.
|
||||
* Seems like the hardware gets upset unless we align
|
||||
|
@ -253,6 +253,9 @@ iwm_nic_lock(struct iwm_softc *sc)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (sc->cmd_hold_nic_awake)
|
||||
return 1;
|
||||
|
||||
IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
|
||||
@ -277,6 +280,9 @@ iwm_nic_lock(struct iwm_softc *sc)
|
||||
void
|
||||
iwm_nic_unlock(struct iwm_softc *sc)
|
||||
{
|
||||
if (sc->cmd_hold_nic_awake)
|
||||
return;
|
||||
|
||||
IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
}
|
||||
@ -583,3 +589,55 @@ iwm_pcie_rx_stop(struct iwm_softc *sc)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
iwm_pcie_clear_cmd_in_flight(struct iwm_softc *sc)
|
||||
{
|
||||
if (!sc->cfg->apmg_wake_up_wa)
|
||||
return;
|
||||
|
||||
if (!sc->cmd_hold_nic_awake) {
|
||||
device_printf(sc->sc_dev,
|
||||
"%s: cmd_hold_nic_awake not set\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
sc->cmd_hold_nic_awake = 0;
|
||||
IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
}
|
||||
|
||||
int
|
||||
iwm_pcie_set_cmd_in_flight(struct iwm_softc *sc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* wake up the NIC to make sure that the firmware will see the host
|
||||
* command - we will let the NIC sleep once all the host commands
|
||||
* returned. This needs to be done only on NICs that have
|
||||
* apmg_wake_up_wa set.
|
||||
*/
|
||||
if (sc->cfg->apmg_wake_up_wa &&
|
||||
!sc->cmd_hold_nic_awake) {
|
||||
|
||||
IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
|
||||
ret = iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
|
||||
(IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP),
|
||||
15000);
|
||||
if (ret == 0) {
|
||||
IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
device_printf(sc->sc_dev,
|
||||
"%s: Failed to wake NIC for hcmd\n", __func__);
|
||||
return EIO;
|
||||
}
|
||||
sc->cmd_hold_nic_awake = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -129,4 +129,7 @@ extern int iwm_start_hw(struct iwm_softc *sc);
|
||||
extern void iwm_set_pwr(struct iwm_softc *sc);
|
||||
extern int iwm_pcie_rx_stop(struct iwm_softc *sc);
|
||||
|
||||
extern int iwm_pcie_set_cmd_in_flight(struct iwm_softc *sc);
|
||||
extern void iwm_pcie_clear_cmd_in_flight(struct iwm_softc *sc);
|
||||
|
||||
#endif
|
||||
|
@ -305,17 +305,10 @@ iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
|
||||
bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
|
||||
IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
|
||||
(IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000)) {
|
||||
device_printf(sc->sc_dev,
|
||||
"%s: acquiring device failed\n", __func__);
|
||||
error = EBUSY;
|
||||
error = iwm_pcie_set_cmd_in_flight(sc);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
ring->queued++;
|
||||
|
||||
#if 0
|
||||
iwm_update_sched(sc, ring->qid, ring->cur, 0, 0);
|
||||
|
@ -389,6 +389,8 @@ enum iwm_device_family {
|
||||
* @host_interrupt_operation_mode: device needs host interrupt operation
|
||||
* mode set
|
||||
* @nvm_hw_section_num: the ID of the HW NVM section
|
||||
* @apmg_wake_up_wa: should the MAC access REQ be asserted when a command
|
||||
* is in flight. This is due to a HW bug in 7260, 3160 and 7265.
|
||||
*/
|
||||
struct iwm_cfg {
|
||||
const char *fw_name;
|
||||
@ -396,6 +398,7 @@ struct iwm_cfg {
|
||||
enum iwm_device_family device_family;
|
||||
int host_interrupt_operation_mode;
|
||||
uint8_t nvm_hw_section_num;
|
||||
int apmg_wake_up_wa;
|
||||
};
|
||||
|
||||
struct iwm_softc {
|
||||
@ -521,6 +524,8 @@ struct iwm_softc {
|
||||
int sc_max_rssi;
|
||||
|
||||
struct iwm_notif_wait_data *sc_notif_wait;
|
||||
|
||||
int cmd_hold_nic_awake;
|
||||
};
|
||||
|
||||
#define IWM_LOCK_INIT(_sc) \
|
||||
|
Loading…
Reference in New Issue
Block a user