Module Name: src Committed By: nonaka Date: Tue Jan 10 07:34:04 UTC 2017
Modified Files: src/sys/dev/pci: if_iwm.c if_iwmvar.h Log Message: Add apmg_wake_up_wa support from DragonFly BSD. To generate a diff of this commit: cvs rdiff -u -r1.58 -r1.59 src/sys/dev/pci/if_iwm.c cvs rdiff -u -r1.12 -r1.13 src/sys/dev/pci/if_iwmvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_iwm.c diff -u src/sys/dev/pci/if_iwm.c:1.58 src/sys/dev/pci/if_iwm.c:1.59 --- src/sys/dev/pci/if_iwm.c:1.58 Tue Jan 10 05:54:03 2017 +++ src/sys/dev/pci/if_iwm.c Tue Jan 10 07:34:04 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: if_iwm.c,v 1.58 2017/01/10 05:54:03 nonaka Exp $ */ +/* $NetBSD: if_iwm.c,v 1.59 2017/01/10 07:34:04 nonaka Exp $ */ /* OpenBSD: if_iwm.c,v 1.148 2016/11/19 21:07:08 stsp Exp */ #define IEEE80211_NO_HT /* @@ -107,7 +107,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.58 2017/01/10 05:54:03 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.59 2017/01/10 07:34:04 nonaka Exp $"); #include <sys/param.h> #include <sys/conf.h> @@ -1003,6 +1003,9 @@ iwm_nic_lock(struct iwm_softc *sc) { int rv = 0; + if (sc->sc_cmd_hold_nic_awake) + return 1; + IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -1025,6 +1028,10 @@ iwm_nic_lock(struct iwm_softc *sc) static void iwm_nic_unlock(struct iwm_softc *sc) { + + if (sc->sc_cmd_hold_nic_awake) + return; + IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } @@ -1284,6 +1291,57 @@ fail: iwm_free_tx_ring(sc, ring); } static void +iwm_clear_cmd_in_flight(struct iwm_softc *sc) +{ + + if (!sc->apmg_wake_up_wa) + return; + + if (!sc->sc_cmd_hold_nic_awake) { + aprint_error_dev(sc->sc_dev, + "cmd_hold_nic_awake not set\n"); + return; + } + + sc->sc_cmd_hold_nic_awake = 0; + IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, + IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} + +static int +iwm_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->apmg_wake_up_wa && !sc->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); + aprint_error_dev(sc->sc_dev, + "failed to wake NIC for hcmd\n"); + return EIO; + } + sc->sc_cmd_hold_nic_awake = 1; + } + + return 0; +} +static void iwm_reset_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring) { int i; @@ -1306,6 +1364,9 @@ iwm_reset_tx_ring(struct iwm_softc *sc, sc->qfullmsk &= ~(1 << ring->qid); ring->queued = 0; ring->cur = 0; + + if (ring->qid == IWM_CMD_QUEUE && sc->sc_cmd_hold_nic_awake) + iwm_clear_cmd_in_flight(sc); } static void @@ -3861,16 +3922,10 @@ iwm_send_cmd(struct iwm_softc *sc, struc (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr, sizeof(*desc), 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)) { - aprint_error_dev(sc->sc_dev, "acquiring device failed\n"); - err = EBUSY; + err = iwm_set_cmd_in_flight(sc); + if (err) goto out; - } + ring->queued++; #if 0 iwm_update_sched(sc, ring->qid, ring->cur, 0, 0); @@ -3999,6 +4054,16 @@ iwm_cmd_done(struct iwm_softc *sc, int q data->m = NULL; } wakeup(&ring->desc[idx]); + + if (((idx + ring->queued) % IWM_TX_RING_COUNT) != ring->cur) { + aprint_error_dev(sc->sc_dev, + "Some HCMDs skipped?: idx=%d queued=%d cur=%d\n", + idx, ring->queued, ring->cur); + } + + KASSERT(ring->queued > 0); + if (--ring->queued == 0) + iwm_clear_cmd_in_flight(sc); } #if 0 @@ -7001,9 +7066,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); - /* * Seems like the hardware gets upset unless we align the write by 8?? */ @@ -7349,6 +7411,7 @@ iwm_attach(device_t parent, device_t sel case PCI_PRODUCT_INTEL_WIFI_LINK_3160_2: sc->sc_fwname = "iwlwifi-3160-16.ucode"; sc->host_interrupt_operation_mode = 1; + sc->apmg_wake_up_wa = 1; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; break; @@ -7356,6 +7419,7 @@ iwm_attach(device_t parent, device_t sel case PCI_PRODUCT_INTEL_WIFI_LINK_3165_2: sc->sc_fwname = "iwlwifi-7265D-16.ucode"; sc->host_interrupt_operation_mode = 0; + sc->apmg_wake_up_wa = 1; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; break; @@ -7363,6 +7427,7 @@ iwm_attach(device_t parent, device_t sel case PCI_PRODUCT_INTEL_WIFI_LINK_7260_2: sc->sc_fwname = "iwlwifi-7260-16.ucode"; sc->host_interrupt_operation_mode = 1; + sc->apmg_wake_up_wa = 1; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; break; @@ -7372,6 +7437,7 @@ iwm_attach(device_t parent, device_t sel IWM_CSR_HW_REV_TYPE_7265D ? "iwlwifi-7265D-16.ucode": "iwlwifi-7265-16.ucode"; sc->host_interrupt_operation_mode = 0; + sc->apmg_wake_up_wa = 1; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; break; @@ -7381,6 +7447,7 @@ iwm_attach(device_t parent, device_t sel case PCI_PRODUCT_INTEL_WIFI_LINK_4165_2: sc->sc_fwname = "iwlwifi-8000C-16.ucode"; sc->host_interrupt_operation_mode = 0; + sc->apmg_wake_up_wa = 0; sc->sc_device_family = IWM_DEVICE_FAMILY_8000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000; break; Index: src/sys/dev/pci/if_iwmvar.h diff -u src/sys/dev/pci/if_iwmvar.h:1.12 src/sys/dev/pci/if_iwmvar.h:1.13 --- src/sys/dev/pci/if_iwmvar.h:1.12 Tue Jan 10 05:54:03 2017 +++ src/sys/dev/pci/if_iwmvar.h Tue Jan 10 07:34:04 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: if_iwmvar.h,v 1.12 2017/01/10 05:54:03 nonaka Exp $ */ +/* $NetBSD: if_iwmvar.h,v 1.13 2017/01/10 07:34:04 nonaka Exp $ */ /* OpenBSD: if_iwmvar.h,v 1.24 2016/09/21 13:53:18 stsp Exp */ /* @@ -466,7 +466,13 @@ struct iwm_softc { struct iwm_notif_statistics sc_stats; int sc_noise; + int sc_cmd_hold_nic_awake; + + /* device needs host interrupt operation mode set */ int host_interrupt_operation_mode; + /* 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. */ + int apmg_wake_up_wa; struct sysctllog *sc_clog;