aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>2015-02-15 07:02:30 -0500
committerKalle Valo <kvalo@codeaurora.org>2015-02-27 03:15:13 -0500
commit2cd0f021b847c4c366dcb064600d8e37944ad84f (patch)
tree30269aa64679c6f2ef54a72525ed039b0d8d4535
parent4ce7bc0a4e555f8519e1a2c8a8569f203bd5727c (diff)
wil6210: boot loader
Introduce boot loader. Instead of the operational firmware, very small boot loader is burned to the on-board flash. Boot loader initializes hardware upon reset, and prepares for low power mode. Boot loader reports MAC address and detects radio chip connected. Driver loads firmware only when bringing up interface. All information required to set up network interface, most important is MAC address, reported by the boot loader The firmware composed of 2 files: - wil6210.fw - firmware itself (compiled code + data) - wil6210.board - board file (various board and radio dependent calibrations and parameters) Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c104
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h16
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c7
7 files changed, 88 insertions, 50 deletions
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 45c3558ec804..3ed16e741a7e 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -549,7 +549,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
549 dev_close(ndev); 549 dev_close(ndev);
550 ndev->flags &= ~IFF_UP; 550 ndev->flags &= ~IFF_UP;
551 rtnl_unlock(); 551 rtnl_unlock();
552 wil_reset(wil); 552 wil_reset(wil, true);
553 553
554 return len; 554 return len;
555} 555}
diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c
index 93c5cc16c515..4428345e5a47 100644
--- a/drivers/net/wireless/ath/wil6210/fw.c
+++ b/drivers/net/wireless/ath/wil6210/fw.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc. 2 * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
3 * 3 *
4 * Permission to use, copy, modify, and/or distribute this software for any 4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above 5 * purpose with or without fee is hereby granted, provided that the above
@@ -20,6 +20,7 @@
20#include "fw.h" 20#include "fw.h"
21 21
22MODULE_FIRMWARE(WIL_FW_NAME); 22MODULE_FIRMWARE(WIL_FW_NAME);
23MODULE_FIRMWARE(WIL_FW2_NAME);
23 24
24/* target operations */ 25/* target operations */
25/* register read */ 26/* register read */
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index d4acf93a9a02..157f5ef384e0 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc. 2 * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
3 * 3 *
4 * Permission to use, copy, modify, and/or distribute this software for any 4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above 5 * purpose with or without fee is hereby granted, provided that the above
@@ -451,8 +451,6 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
451 } 451 }
452 return -EINVAL; 452 return -EINVAL;
453 } 453 }
454 /* Mark FW as loaded from host */
455 S(RGF_USER_USAGE_6, 1);
456 454
457 return rc; 455 return rc;
458} 456}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index b04e0afdcb21..acbbd272a41e 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;
29module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); 29module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
30MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); 30MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
31 31
32static bool no_fw_load = true;
33module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
34MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
35
36/* if not set via modparam, will be set to default value of 1/8 of 32/* if not set via modparam, will be set to default value of 1/8 of
37 * rx ring size during init flow 33 * rx ring size during init flow
38 */ 34 */
@@ -532,6 +528,8 @@ static int wil_target_reset(struct wil6210_priv *wil)
532 528
533 wil_halt_cpu(wil); 529 wil_halt_cpu(wil);
534 530
531 /* clear all boot loader "ready" bits */
532 W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0);
535 /* Clear Fw Download notification */ 533 /* Clear Fw Download notification */
536 C(RGF_USER_USAGE_6, BIT(0)); 534 C(RGF_USER_USAGE_6, BIT(0));
537 535
@@ -583,16 +581,16 @@ static int wil_target_reset(struct wil6210_priv *wil)
583 /* TODO: check order here!!! Erez code is different */ 581 /* TODO: check order here!!! Erez code is different */
584 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); 582 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
585 583
586 /* wait until device ready. typical time is 200..250 msec */ 584 /* wait until device ready. typical time is 20..80 msec */
587 do { 585 do {
588 msleep(RST_DELAY); 586 msleep(RST_DELAY);
589 x = R(RGF_USER_HW_MACHINE_STATE); 587 x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready));
590 if (delay++ > RST_COUNT) { 588 if (delay++ > RST_COUNT) {
591 wil_err(wil, "Reset not completed, hw_state 0x%08x\n", 589 wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
592 x); 590 x);
593 return -ETIME; 591 return -ETIME;
594 } 592 }
595 } while (x != HW_MACHINE_BOOT_DONE); 593 } while (!(x & BIT_BL_READY));
596 594
597 if (!is_reset_v2) 595 if (!is_reset_v2)
598 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); 596 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
@@ -603,11 +601,6 @@ static int wil_target_reset(struct wil6210_priv *wil)
603 return 0; 601 return 0;
604} 602}
605 603
606#undef R
607#undef W
608#undef S
609#undef C
610
611void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) 604void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
612{ 605{
613 le32_to_cpus(&r->base); 606 le32_to_cpus(&r->base);
@@ -617,6 +610,32 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
617 le32_to_cpus(&r->head); 610 le32_to_cpus(&r->head);
618} 611}
619 612
613static int wil_get_bl_info(struct wil6210_priv *wil)
614{
615 struct net_device *ndev = wil_to_ndev(wil);
616 struct RGF_BL bl;
617
618 wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl));
619 le32_to_cpus(&bl.ready);
620 le32_to_cpus(&bl.version);
621 le32_to_cpus(&bl.rf_type);
622 le32_to_cpus(&bl.baseband_type);
623
624 if (!is_valid_ether_addr(bl.mac_address)) {
625 wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address);
626 return -EINVAL;
627 }
628
629 ether_addr_copy(ndev->perm_addr, bl.mac_address);
630 if (!is_valid_ether_addr(ndev->dev_addr))
631 ether_addr_copy(ndev->dev_addr, bl.mac_address);
632 wil_info(wil,
633 "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n",
634 bl.version, bl.mac_address, bl.rf_type, bl.baseband_type);
635
636 return 0;
637}
638
620static int wil_wait_for_fw_ready(struct wil6210_priv *wil) 639static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
621{ 640{
622 ulong to = msecs_to_jiffies(1000); 641 ulong to = msecs_to_jiffies(1000);
@@ -637,7 +656,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
637 * After calling this routine, you're expected to reload 656 * After calling this routine, you're expected to reload
638 * the firmware. 657 * the firmware.
639 */ 658 */
640int wil_reset(struct wil6210_priv *wil) 659int wil_reset(struct wil6210_priv *wil, bool load_fw)
641{ 660{
642 int rc; 661 int rc;
643 662
@@ -675,30 +694,36 @@ int wil_reset(struct wil6210_priv *wil)
675 if (rc) 694 if (rc)
676 return rc; 695 return rc;
677 696
678 if (!no_fw_load) { 697 rc = wil_get_bl_info(wil);
679 wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME); 698 if (rc)
699 return rc;
700
701 if (load_fw) {
702 wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME,
703 WIL_FW2_NAME);
704
680 wil_halt_cpu(wil); 705 wil_halt_cpu(wil);
681 /* Loading f/w from the file */ 706 /* Loading f/w from the file */
682 rc = wil_request_firmware(wil, WIL_FW_NAME); 707 rc = wil_request_firmware(wil, WIL_FW_NAME);
683 if (rc) 708 if (rc)
684 return rc; 709 return rc;
710 rc = wil_request_firmware(wil, WIL_FW2_NAME);
711 if (rc)
712 return rc;
713
714 /* Mark FW as loaded from host */
715 S(RGF_USER_USAGE_6, 1);
685 716
686 /* clear any interrupts which on-card-firmware may have set */ 717 /* clear any interrupts which on-card-firmware
718 * may have set
719 */
687 wil6210_clear_irq(wil); 720 wil6210_clear_irq(wil);
688 { /* CAF_ICR - clear and mask */ 721 /* CAF_ICR - clear and mask */
689 u32 a = HOSTADDR(RGF_CAF_ICR) + 722 /* it is W1C, clear by writing back same value */
690 offsetof(struct RGF_ICR, ICR); 723 S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
691 u32 m = HOSTADDR(RGF_CAF_ICR) + 724 W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
692 offsetof(struct RGF_ICR, IMV); 725
693 u32 icr = ioread32(wil->csr + a);
694
695 iowrite32(icr, wil->csr + a); /* W1C */
696 iowrite32(~0, wil->csr + m);
697 wmb(); /* wait for completion */
698 }
699 wil_release_cpu(wil); 726 wil_release_cpu(wil);
700 } else {
701 wil_info(wil, "Use firmware from on-card flash\n");
702 } 727 }
703 728
704 /* init after reset */ 729 /* init after reset */
@@ -706,15 +731,22 @@ int wil_reset(struct wil6210_priv *wil)
706 reinit_completion(&wil->wmi_ready); 731 reinit_completion(&wil->wmi_ready);
707 reinit_completion(&wil->wmi_call); 732 reinit_completion(&wil->wmi_call);
708 733
709 wil_configure_interrupt_moderation(wil); 734 if (load_fw) {
710 wil_unmask_irq(wil); 735 wil_configure_interrupt_moderation(wil);
736 wil_unmask_irq(wil);
711 737
712 /* we just started MAC, wait for FW ready */ 738 /* we just started MAC, wait for FW ready */
713 rc = wil_wait_for_fw_ready(wil); 739 rc = wil_wait_for_fw_ready(wil);
740 }
714 741
715 return rc; 742 return rc;
716} 743}
717 744
745#undef R
746#undef W
747#undef S
748#undef C
749
718void wil_fw_error_recovery(struct wil6210_priv *wil) 750void wil_fw_error_recovery(struct wil6210_priv *wil)
719{ 751{
720 wil_dbg_misc(wil, "starting fw error recovery\n"); 752 wil_dbg_misc(wil, "starting fw error recovery\n");
@@ -730,7 +762,7 @@ int __wil_up(struct wil6210_priv *wil)
730 762
731 WARN_ON(!mutex_is_locked(&wil->mutex)); 763 WARN_ON(!mutex_is_locked(&wil->mutex));
732 764
733 rc = wil_reset(wil); 765 rc = wil_reset(wil, true);
734 if (rc) 766 if (rc)
735 return rc; 767 return rc;
736 768
@@ -837,7 +869,7 @@ int __wil_down(struct wil6210_priv *wil)
837 if (!iter) 869 if (!iter)
838 wil_err(wil, "timeout waiting for idle FW/HW\n"); 870 wil_err(wil, "timeout waiting for idle FW/HW\n");
839 871
840 wil_rx_fini(wil); 872 wil_reset(wil, false);
841 873
842 return 0; 874 return 0;
843} 875}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 3dd26709ccb2..f7c165d35343 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -150,7 +150,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
150 150
151 /* need reset here to obtain MAC */ 151 /* need reset here to obtain MAC */
152 mutex_lock(&wil->mutex); 152 mutex_lock(&wil->mutex);
153 rc = wil_reset(wil); 153 rc = wil_reset(wil, false);
154 mutex_unlock(&wil->mutex); 154 mutex_unlock(&wil->mutex);
155 if (debug_fw) 155 if (debug_fw)
156 rc = 0; 156 rc = 0;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 94611568fc9a..cfe43d212e1f 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -29,7 +29,8 @@ extern unsigned short rx_ring_overflow_thrsh;
29extern int agg_wsize; 29extern int agg_wsize;
30 30
31#define WIL_NAME "wil6210" 31#define WIL_NAME "wil6210"
32#define WIL_FW_NAME "wil6210.fw" 32#define WIL_FW_NAME "wil6210.fw" /* code */
33#define WIL_FW2_NAME "wil6210.board" /* board & radio parameters */
33 34
34#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ 35#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
35 36
@@ -120,6 +121,16 @@ struct RGF_ICR {
120 u32 IMC; /* Mask Clear, write 1 to clear */ 121 u32 IMC; /* Mask Clear, write 1 to clear */
121} __packed; 122} __packed;
122 123
124struct RGF_BL {
125 u32 ready; /* 0x880A3C bit [0] */
126#define BIT_BL_READY BIT(0)
127 u32 version; /* 0x880A40 version of the BL struct */
128 u32 rf_type; /* 0x880A44 ID of the connected RF */
129 u32 baseband_type; /* 0x880A48 ID of the baseband */
130 u8 mac_address[ETH_ALEN]; /* 0x880A4C permanent MAC */
131 u8 pad[2];
132} __packed;
133
123/* registers - FW addresses */ 134/* registers - FW addresses */
124#define RGF_USER_USAGE_1 (0x880004) 135#define RGF_USER_USAGE_1 (0x880004)
125#define RGF_USER_USAGE_6 (0x880018) 136#define RGF_USER_USAGE_6 (0x880018)
@@ -130,6 +141,7 @@ struct RGF_ICR {
130#define RGF_USER_MAC_CPU_0 (0x8801fc) 141#define RGF_USER_MAC_CPU_0 (0x8801fc)
131 #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ 142 #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */
132#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) 143#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
144#define RGF_USER_BL (0x880A3C) /* Boot Loader */
133#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ 145#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */
134#define RGF_USER_CLKS_CTL_0 (0x880abc) 146#define RGF_USER_CLKS_CTL_0 (0x880abc)
135 #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */ 147 #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */
@@ -658,7 +670,7 @@ int wil_if_add(struct wil6210_priv *wil);
658void wil_if_remove(struct wil6210_priv *wil); 670void wil_if_remove(struct wil6210_priv *wil);
659int wil_priv_init(struct wil6210_priv *wil); 671int wil_priv_init(struct wil6210_priv *wil);
660void wil_priv_deinit(struct wil6210_priv *wil); 672void wil_priv_deinit(struct wil6210_priv *wil);
661int wil_reset(struct wil6210_priv *wil); 673int wil_reset(struct wil6210_priv *wil, bool no_fw);
662void wil_fw_error_recovery(struct wil6210_priv *wil); 674void wil_fw_error_recovery(struct wil6210_priv *wil);
663void wil_set_recovery_state(struct wil6210_priv *wil, int state); 675void wil_set_recovery_state(struct wil6210_priv *wil, int state);
664int wil_up(struct wil6210_priv *wil); 676int wil_up(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 0f3e4334c8e3..e60186cf4e3c 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -281,7 +281,6 @@ int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
281/*=== Event handlers ===*/ 281/*=== Event handlers ===*/
282static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) 282static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
283{ 283{
284 struct net_device *ndev = wil_to_ndev(wil);
285 struct wireless_dev *wdev = wil->wdev; 284 struct wireless_dev *wdev = wil->wdev;
286 struct wmi_ready_event *evt = d; 285 struct wmi_ready_event *evt = d;
287 286
@@ -290,11 +289,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
290 289
291 wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, 290 wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version,
292 evt->mac, wil->n_mids); 291 evt->mac, wil->n_mids);
293 292 /* ignore MAC address, we already have it from the boot loader */
294 if (!is_valid_ether_addr(ndev->dev_addr)) {
295 memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
296 memcpy(ndev->perm_addr, evt->mac, ETH_ALEN);
297 }
298 snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), 293 snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
299 "%d", wil->fw_version); 294 "%d", wil->fw_version);
300} 295}