summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/wil6210/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/main.c')
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c198
1 files changed, 128 insertions, 70 deletions
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 6ca6193ab8a6..2fb04c51da53 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -21,6 +21,7 @@
#include "wil6210.h"
#include "txrx.h"
#include "wmi.h"
+#include "boot_loader.h"
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
@@ -270,8 +271,7 @@ static void wil_scan_timer_fn(ulong x)
clear_bit(wil_status_fwready, wil->status);
wil_err(wil, "Scan timeout detected, start fw error recovery\n");
- wil->recovery_state = fw_recovery_pending;
- schedule_work(&wil->fw_error_worker);
+ wil_fw_error_recovery(wil);
}
static int wil_wait_for_recovery(struct wil6210_priv *wil)
@@ -528,26 +528,16 @@ void wil_priv_deinit(struct wil6210_priv *wil)
destroy_workqueue(wil->wmi_wq);
}
-/* target operations */
-/* register read */
-#define R(a) ioread32(wil->csr + HOSTADDR(a))
-/* register write. wmb() to make sure it is completed */
-#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
-/* register set = read, OR, write */
-#define S(a, v) W(a, R(a) | v)
-/* register clear = read, AND with inverted, write */
-#define C(a, v) W(a, R(a) & ~v)
-
static inline void wil_halt_cpu(struct wil6210_priv *wil)
{
- W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
- W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
+ wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
+ wil_w(wil, RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
}
static inline void wil_release_cpu(struct wil6210_priv *wil)
{
/* Start CPU */
- W(RGF_USER_USER_CPU_0, 1);
+ wil_w(wil, RGF_USER_USER_CPU_0, 1);
}
static int wil_target_reset(struct wil6210_priv *wil)
@@ -558,56 +548,60 @@ static int wil_target_reset(struct wil6210_priv *wil)
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
/* Clear MAC link up */
- S(RGF_HP_CTRL, BIT(15));
- S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
- S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
+ wil_s(wil, RGF_HP_CTRL, BIT(15));
+ wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
+ wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
wil_halt_cpu(wil);
/* clear all boot loader "ready" bits */
- W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0);
+ wil_w(wil, RGF_USER_BL +
+ offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0);
/* Clear Fw Download notification */
- C(RGF_USER_USAGE_6, BIT(0));
+ wil_c(wil, RGF_USER_USAGE_6, BIT(0));
- S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
+ wil_s(wil, 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);
+ x = wil_r(wil, 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);
+ wil_c(wil, 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);
+ wil_c(wil, 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);
+ wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
+ wil_w(wil, 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, 0x000000f0);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
- W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
- W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
+ wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
+ wil_w(wil, 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);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
+ /* reset A2 PCIE AHB */
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
+ wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
/* wait until device ready. typical time is 20..80 msec */
do {
msleep(RST_DELAY);
- x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready));
+ x = wil_r(wil, RGF_USER_BL +
+ offsetof(struct bl_dedicated_registers_v0,
+ boot_loader_ready));
if (x1 != x) {
wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
x1 = x;
@@ -617,13 +611,13 @@ static int wil_target_reset(struct wil6210_priv *wil)
x);
return -ETIME;
}
- } while (x != BIT_BL_READY);
+ } while (x != BL_READY);
- C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
+ wil_c(wil, 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_s(wil, 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;
@@ -641,29 +635,93 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
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);
+ union {
+ struct bl_dedicated_registers_v0 bl0;
+ struct bl_dedicated_registers_v1 bl1;
+ } bl;
+ u32 bl_ver;
+ u8 *mac;
+ u16 rf_status;
+
+ wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL),
+ sizeof(bl));
+ bl_ver = le32_to_cpu(bl.bl0.boot_loader_struct_version);
+ mac = bl.bl0.mac_address;
+
+ if (bl_ver == 0) {
+ le32_to_cpus(&bl.bl0.rf_type);
+ le32_to_cpus(&bl.bl0.baseband_type);
+ rf_status = 0; /* actually, unknown */
+ wil_info(wil,
+ "Boot Loader struct v%d: MAC = %pM RF = 0x%08x bband = 0x%08x\n",
+ bl_ver, mac,
+ bl.bl0.rf_type, bl.bl0.baseband_type);
+ wil_info(wil, "Boot Loader build unknown for struct v0\n");
+ } else {
+ le16_to_cpus(&bl.bl1.rf_type);
+ rf_status = le16_to_cpu(bl.bl1.rf_status);
+ le32_to_cpus(&bl.bl1.baseband_type);
+ le16_to_cpus(&bl.bl1.bl_version_subminor);
+ le16_to_cpus(&bl.bl1.bl_version_build);
+ wil_info(wil,
+ "Boot Loader struct v%d: MAC = %pM RF = 0x%04x (status 0x%04x) bband = 0x%08x\n",
+ bl_ver, mac,
+ bl.bl1.rf_type, rf_status,
+ bl.bl1.baseband_type);
+ wil_info(wil, "Boot Loader build %d.%d.%d.%d\n",
+ bl.bl1.bl_version_major, bl.bl1.bl_version_minor,
+ bl.bl1.bl_version_subminor, bl.bl1.bl_version_build);
+ }
- if (!is_valid_ether_addr(bl.mac_address)) {
- wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address);
+ if (!is_valid_ether_addr(mac)) {
+ wil_err(wil, "BL: Invalid MAC %pM\n", mac);
return -EINVAL;
}
- ether_addr_copy(ndev->perm_addr, bl.mac_address);
+ ether_addr_copy(ndev->perm_addr, mac);
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);
+ ether_addr_copy(ndev->dev_addr, mac);
+
+ if (rf_status) {/* bad RF cable? */
+ wil_err(wil, "RF communication error 0x%04x",
+ rf_status);
+ return -EAGAIN;
+ }
return 0;
}
+static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err)
+{
+ u32 bl_assert_code, bl_assert_blink, bl_magic_number;
+ u32 bl_ver = wil_r(wil, RGF_USER_BL +
+ offsetof(struct bl_dedicated_registers_v0,
+ boot_loader_struct_version));
+
+ if (bl_ver < 2)
+ return;
+
+ bl_assert_code = wil_r(wil, RGF_USER_BL +
+ offsetof(struct bl_dedicated_registers_v1,
+ bl_assert_code));
+ bl_assert_blink = wil_r(wil, RGF_USER_BL +
+ offsetof(struct bl_dedicated_registers_v1,
+ bl_assert_blink));
+ bl_magic_number = wil_r(wil, RGF_USER_BL +
+ offsetof(struct bl_dedicated_registers_v1,
+ bl_magic_number));
+
+ if (is_err) {
+ wil_err(wil,
+ "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n",
+ bl_assert_code, bl_assert_blink, bl_magic_number);
+ } else {
+ wil_dbg_misc(wil,
+ "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n",
+ bl_assert_code, bl_assert_blink, bl_magic_number);
+ }
+}
+
static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
{
ulong to = msecs_to_jiffies(1000);
@@ -690,9 +748,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil_dbg_misc(wil, "%s()\n", __func__);
- if (wil->hw_version == HW_VER_UNKNOWN)
- return -ENODEV;
-
WARN_ON(!mutex_is_locked(&wil->mutex));
WARN_ON(test_bit(wil_status_napi_en, wil->status));
@@ -707,6 +762,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
return 0;
}
+ if (wil->hw_version == HW_VER_UNKNOWN)
+ return -ENODEV;
+
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
wil_bcast_fini(wil);
@@ -729,12 +787,17 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
flush_workqueue(wil->wq_service);
flush_workqueue(wil->wmi_wq);
+ wil_bl_crash_info(wil, false);
rc = wil_target_reset(wil);
wil_rx_fini(wil);
- if (rc)
+ if (rc) {
+ wil_bl_crash_info(wil, true);
return rc;
+ }
rc = wil_get_bl_info(wil);
+ if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
+ rc = 0;
if (rc)
return rc;
@@ -752,7 +815,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
return rc;
/* Mark FW as loaded from host */
- S(RGF_USER_USAGE_6, 1);
+ wil_s(wil, RGF_USER_USAGE_6, 1);
/* clear any interrupts which on-card-firmware
* may have set
@@ -760,8 +823,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil6210_clear_irq(wil);
/* 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_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
+ wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
wil_release_cpu(wil);
}
@@ -785,11 +848,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
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");