diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/main.c')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/main.c | 202 |
1 files changed, 128 insertions, 74 deletions
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index b04e0afdcb21..c2a238426425 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -29,10 +29,6 @@ bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); -static bool no_fw_load = true; -module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); - /* if not set via modparam, will be set to default value of 1/8 of * rx ring size during init flow */ @@ -72,6 +68,7 @@ MODULE_PARM_DESC(mtu_max, " Max MTU value."); static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; +static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; static int ring_order_set(const char *val, const struct kernel_param *kp) { @@ -220,6 +217,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: + wil_bcast_fini(wil); netif_tx_stop_all_queues(ndev); netif_carrier_off(ndev); @@ -364,6 +362,35 @@ static int wil_find_free_vring(struct wil6210_priv *wil) return -EINVAL; } +int wil_bcast_init(struct wil6210_priv *wil) +{ + int ri = wil->bcast_vring, rc; + + if ((ri >= 0) && wil->vring_tx[ri].va) + return 0; + + ri = wil_find_free_vring(wil); + if (ri < 0) + return ri; + + rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order); + if (rc == 0) + wil->bcast_vring = ri; + + return rc; +} + +void wil_bcast_fini(struct wil6210_priv *wil) +{ + int ri = wil->bcast_vring; + + if (ri < 0) + return; + + wil->bcast_vring = -1; + wil_vring_fini_tx(wil, ri); +} + static void wil_connect_worker(struct work_struct *work) { int rc; @@ -411,6 +438,7 @@ int wil_priv_init(struct wil6210_priv *wil) init_completion(&wil->wmi_call); wil->pending_connect_cid = -1; + wil->bcast_vring = -1; setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil); @@ -520,8 +548,6 @@ static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 x; - bool is_reset_v2 = test_bit(hw_capability_reset_v2, - wil->hw_capabilities); wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); @@ -532,82 +558,67 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); + /* clear all boot loader "ready" bits */ + W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0); /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); - if (is_reset_v2) { - S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); - /* XTAL stabilization should take about 3ms */ - usleep_range(5000, 7000); - x = R(RGF_CAF_PLL_LOCK_STATUS); - if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { - wil_err(wil, "Xtal stabilization timeout\n" - "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); - return -ETIME; - } - /* switch 10k to XTAL*/ - C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); - /* 40 MHz */ - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); - - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); + S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); + /* XTAL stabilization should take about 3ms */ + usleep_range(5000, 7000); + x = R(RGF_CAF_PLL_LOCK_STATUS); + if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { + wil_err(wil, "Xtal stabilization timeout\n" + "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); + return -ETIME; } + /* switch 10k to XTAL*/ + C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); + /* 40 MHz */ + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); + + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, - is_reset_v2 ? 0x000000f0 : 0x00000170); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); - if (is_reset_v2) { - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); - } + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - if (is_reset_v2) { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); - /* reset A2 PCIE AHB */ - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } else { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */ - /* TODO: check order here!!! Erez code is different */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - /* wait until device ready. typical time is 200..250 msec */ + /* wait until device ready. typical time is 20..80 msec */ do { msleep(RST_DELAY); - x = R(RGF_USER_HW_MACHINE_STATE); + x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); if (delay++ > RST_COUNT) { - wil_err(wil, "Reset not completed, hw_state 0x%08x\n", + wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", x); return -ETIME; } - } while (x != HW_MACHINE_BOOT_DONE); - - if (!is_reset_v2) - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); + } while (!(x & BIT_BL_READY)); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + /* enable fix for HW bug related to the SA/DA swap in AP Rx */ + S(RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | + BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; } -#undef R -#undef W -#undef S -#undef C - void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) { le32_to_cpus(&r->base); @@ -617,6 +628,32 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) le32_to_cpus(&r->head); } +static int wil_get_bl_info(struct wil6210_priv *wil) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct RGF_BL bl; + + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl)); + le32_to_cpus(&bl.ready); + le32_to_cpus(&bl.version); + le32_to_cpus(&bl.rf_type); + le32_to_cpus(&bl.baseband_type); + + if (!is_valid_ether_addr(bl.mac_address)) { + wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address); + return -EINVAL; + } + + ether_addr_copy(ndev->perm_addr, bl.mac_address); + if (!is_valid_ether_addr(ndev->dev_addr)) + ether_addr_copy(ndev->dev_addr, bl.mac_address); + wil_info(wil, + "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n", + bl.version, bl.mac_address, bl.rf_type, bl.baseband_type); + + return 0; +} + static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); @@ -637,7 +674,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) * After calling this routine, you're expected to reload * the firmware. */ -int wil_reset(struct wil6210_priv *wil) +int wil_reset(struct wil6210_priv *wil, bool load_fw) { int rc; @@ -651,6 +688,7 @@ int wil_reset(struct wil6210_priv *wil) cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); + wil_bcast_fini(wil); /* prevent NAPI from being scheduled */ bitmap_zero(wil->status, wil_status_last); @@ -675,46 +713,62 @@ int wil_reset(struct wil6210_priv *wil) if (rc) return rc; - if (!no_fw_load) { - wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME); + rc = wil_get_bl_info(wil); + if (rc) + return rc; + + if (load_fw) { + wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME, + WIL_FW2_NAME); + wil_halt_cpu(wil); /* Loading f/w from the file */ rc = wil_request_firmware(wil, WIL_FW_NAME); if (rc) return rc; + rc = wil_request_firmware(wil, WIL_FW2_NAME); + if (rc) + return rc; + + /* Mark FW as loaded from host */ + S(RGF_USER_USAGE_6, 1); - /* clear any interrupts which on-card-firmware may have set */ + /* clear any interrupts which on-card-firmware + * may have set + */ wil6210_clear_irq(wil); - { /* CAF_ICR - clear and mask */ - u32 a = HOSTADDR(RGF_CAF_ICR) + - offsetof(struct RGF_ICR, ICR); - u32 m = HOSTADDR(RGF_CAF_ICR) + - offsetof(struct RGF_ICR, IMV); - u32 icr = ioread32(wil->csr + a); - - iowrite32(icr, wil->csr + a); /* W1C */ - iowrite32(~0, wil->csr + m); - wmb(); /* wait for completion */ - } + /* CAF_ICR - clear and mask */ + /* it is W1C, clear by writing back same value */ + S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + wil_release_cpu(wil); - } else { - wil_info(wil, "Use firmware from on-card flash\n"); } /* init after reset */ wil->pending_connect_cid = -1; + wil->ap_isolate = 0; reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); - wil_configure_interrupt_moderation(wil); - wil_unmask_irq(wil); + if (load_fw) { + wil_configure_interrupt_moderation(wil); + wil_unmask_irq(wil); - /* we just started MAC, wait for FW ready */ - rc = wil_wait_for_fw_ready(wil); + /* we just started MAC, wait for FW ready */ + rc = wil_wait_for_fw_ready(wil); + if (rc == 0) /* check FW is responsive */ + rc = wmi_echo(wil); + } return rc; } +#undef R +#undef W +#undef S +#undef C + void wil_fw_error_recovery(struct wil6210_priv *wil) { wil_dbg_misc(wil, "starting fw error recovery\n"); @@ -730,7 +784,7 @@ int __wil_up(struct wil6210_priv *wil) WARN_ON(!mutex_is_locked(&wil->mutex)); - rc = wil_reset(wil); + rc = wil_reset(wil, true); if (rc) return rc; @@ -837,7 +891,7 @@ int __wil_down(struct wil6210_priv *wil) if (!iter) wil_err(wil, "timeout waiting for idle FW/HW\n"); - wil_rx_fini(wil); + wil_reset(wil, false); return 0; } |