Loading drivers/net/wireless/ath/wil6210/boot_loader.h +8 −1 Original line number Diff line number Diff line /* Copyright (c) 2015 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -39,7 +40,8 @@ struct bl_dedicated_registers_v1 { /* valid only for version 2 and above */ __le32 bl_assert_code; /* 0x880A58 BL Assert code */ __le32 bl_assert_blink; /* 0x880A5C BL Assert Branch */ __le32 bl_reserved[22]; /* 0x880A60 - 0x880AB4 */ __le32 bl_shutdown_handshake; /* 0x880A60 BL cleaner shutdown */ __le32 bl_reserved[21]; /* 0x880A64 - 0x880AB4 */ __le32 bl_magic_number; /* 0x880AB8 BL Magic number */ } __packed; Loading @@ -58,4 +60,9 @@ struct bl_dedicated_registers_v0 { u8 mac_address[6]; /* 0x880A4c BL mac address */ } __packed; /* bits for bl_shutdown_handshake */ #define BL_SHUTDOWN_HS_GRTD BIT(0) #define BL_SHUTDOWN_HS_RTD BIT(1) #define BL_SHUTDOWN_HS_PROT_VER(x) WIL_GET_BITS(x, 28, 31) #endif /* BOOT_LOADER_EXPORT_H_ */ drivers/net/wireless/ath/wil6210/interrupt.c +4 −2 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -395,8 +396,9 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) wil6210_mask_irq_misc(wil, false); if (isr & ISR_MISC_FW_ERROR) { u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE); u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE); u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr); u32 ucode_assert_code = wil_r(wil, wil->rgf_ucode_assert_code_addr); wil_err(wil, "Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n", Loading drivers/net/wireless/ath/wil6210/main.c +185 −25 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -642,6 +643,98 @@ void wil_priv_deinit(struct wil6210_priv *wil) destroy_workqueue(wil->wmi_wq); } static void wil_shutdown_bl(struct wil6210_priv *wil) { u32 val; wil_s(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v1, bl_shutdown_handshake), BL_SHUTDOWN_HS_GRTD); usleep_range(100, 150); val = wil_r(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v1, bl_shutdown_handshake)); if (val & BL_SHUTDOWN_HS_RTD) { wil_dbg_misc(wil, "BL is ready for halt\n"); return; } wil_err(wil, "BL did not report ready for halt\n"); } /* this format is used by ARC embedded CPU for instruction memory */ static inline u32 ARC_me_imm32(u32 d) { return ((d & 0xffff0000) >> 16) | ((d & 0x0000ffff) << 16); } /* defines access to interrupt vectors for wil_freeze_bl */ #define ARC_IRQ_VECTOR_OFFSET(N) ((N) * 8) /* ARC long jump instruction */ #define ARC_JAL_INST (0x20200f80) static void wil_freeze_bl(struct wil6210_priv *wil) { u32 jal, upc, saved; u32 ivt3 = ARC_IRQ_VECTOR_OFFSET(3); jal = wil_r(wil, wil->iccm_base + ivt3); if (jal != ARC_me_imm32(ARC_JAL_INST)) { wil_dbg_misc(wil, "invalid IVT entry found, skipping\n"); return; } /* prevent the target from entering deep sleep * and disabling memory access */ saved = wil_r(wil, RGF_USER_USAGE_8); wil_w(wil, RGF_USER_USAGE_8, saved | BIT_USER_PREVENT_DEEP_SLEEP); usleep_range(20, 25); /* let the BL process the bit */ /* redirect to endless loop in the INT_L1 context and let it trap */ wil_w(wil, wil->iccm_base + ivt3 + 4, ARC_me_imm32(ivt3)); usleep_range(20, 25); /* let the BL get into the trap */ /* verify the BL is frozen */ upc = wil_r(wil, RGF_USER_CPU_PC); if (upc < ivt3 || (upc > (ivt3 + 8))) wil_dbg_misc(wil, "BL freeze failed, PC=0x%08X\n", upc); wil_w(wil, RGF_USER_USAGE_8, saved); } static void wil_bl_prepare_halt(struct wil6210_priv *wil) { u32 tmp, ver; /* before halting device CPU driver must make sure BL is not accessing * host memory. This is done differently depending on BL version: * 1. For very old BL versions the procedure is skipped * (not supported). * 2. For old BL version we use a special trick to freeze the BL * 3. For new BL versions we shutdown the BL using handshake procedure. */ tmp = wil_r(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, boot_loader_struct_version)); if (!tmp) { wil_dbg_misc(wil, "old BL, skipping halt preperation\n"); return; } tmp = wil_r(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v1, bl_shutdown_handshake)); ver = BL_SHUTDOWN_HS_PROT_VER(tmp); if (ver > 0) wil_shutdown_bl(wil); else wil_freeze_bl(wil); } static inline void wil_halt_cpu(struct wil6210_priv *wil) { wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); Loading Loading @@ -675,7 +768,7 @@ static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode) } } static int wil_target_reset(struct wil6210_priv *wil) static int wil_target_reset(struct wil6210_priv *wil, int no_flash) { int delay = 0; u32 x, x1 = 0; Loading @@ -689,9 +782,16 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); if (!no_flash) { /* clear all boot loader "ready" bits */ wil_w(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); /* this should be safe to write even with old BLs */ wil_w(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v1, bl_shutdown_handshake), 0); } /* Clear Fw Download notification */ wil_c(wil, RGF_USER_USAGE_6, BIT(0)); Loading Loading @@ -732,13 +832,25 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); /* wait until device ready. typical time is 20..80 msec */ if (no_flash) do { msleep(RST_DELAY); x = wil_r(wil, USER_EXT_USER_PMU_3); if (delay++ > RST_COUNT) { wil_err(wil, "Reset not completed, PMU_3 0x%08x\n", x); return -ETIME; } } while ((x & BIT_PMU_DEVICE_RDY) == 0); else do { msleep(RST_DELAY); 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); wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x1 = x; } if (delay++ > RST_COUNT) { Loading @@ -754,6 +866,21 @@ static int wil_target_reset(struct wil6210_priv *wil) 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); if (no_flash) { /* Reset OTP HW vectors to fit 40MHz */ wil_w(wil, RGF_USER_XPM_IFC_RD_TIME1, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME2, 0x20027); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME3, 0x1); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME4, 0x20027); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME5, 0x30003); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME6, 0x20002); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME7, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME8, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME9, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME10, 0x60001); wil_w(wil, RGF_USER_XPM_RD_DOUT_SAMPLE_TIME, 0x57); } wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; } Loading Loading @@ -911,6 +1038,27 @@ static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err) } } static int wil_get_otp_info(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); struct wiphy *wiphy = wil_to_wiphy(wil); u8 mac[8]; wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(RGF_OTP_MAC), sizeof(mac)); if (!is_valid_ether_addr(mac)) { wil_err(wil, "Invalid MAC %pM\n", mac); return -EINVAL; } ether_addr_copy(ndev->perm_addr, mac); ether_addr_copy(wiphy->perm_addr, mac); if (!is_valid_ether_addr(ndev->dev_addr)) ether_addr_copy(ndev->dev_addr, mac); return 0; } static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); Loading Loading @@ -1004,6 +1152,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) { int rc; unsigned long status_flags = BIT(wil_status_resetting); int no_flash; wil_dbg_misc(wil, "reset\n"); Loading Loading @@ -1082,20 +1231,28 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); no_flash = test_bit(hw_capa_no_flash, wil->hw_capa); if (!no_flash) wil_bl_crash_info(wil, false); wil_disable_irq(wil); rc = wil_target_reset(wil); rc = wil_target_reset(wil, no_flash); wil6210_clear_irq(wil); wil_enable_irq(wil); wil_rx_fini(wil); if (rc) { if (!no_flash) wil_bl_crash_info(wil, true); goto out; } if (no_flash) { rc = wil_get_otp_info(wil); } else { rc = wil_get_bl_info(wil); if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ rc = 0; } if (rc) goto out; Loading @@ -1104,6 +1261,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil_info(wil, "Use firmware <%s> + board <%s>\n", wil->wil_fw_name, WIL_BOARD_FILE_NAME); if (!no_flash) wil_bl_prepare_halt(wil); wil_halt_cpu(wil); memset(wil->fw_version, 0, sizeof(wil->fw_version)); /* Loading f/w from the file */ Loading drivers/net/wireless/ath/wil6210/pcie_bus.c +36 −4 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -39,15 +40,16 @@ static int wil6210_pm_notify(struct notifier_block *notify_block, #endif /* CONFIG_PM */ static void wil_set_capabilities(struct wil6210_priv *wil) int wil_set_capabilities(struct wil6210_priv *wil) { const char *wil_fw_name; u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) & RGF_USER_REVISION_ID_MASK); int platform_capa; struct fw_map *iccm_section; bitmap_zero(wil->hw_capabilities, hw_capability_last); bitmap_zero(wil->hw_capa, hw_capa_last); bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX); bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX); wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT : Loading Loading @@ -75,15 +77,38 @@ void wil_set_capabilities(struct wil6210_priv *wil) wil->hw_version = HW_VER_UNKNOWN; break; } memcpy(fw_mapping, sparrow_fw_mapping, sizeof(sparrow_fw_mapping)); wil->rgf_fw_assert_code_addr = SPARROW_RGF_FW_ASSERT_CODE; wil->rgf_ucode_assert_code_addr = SPARROW_RGF_UCODE_ASSERT_CODE; break; case JTAG_DEV_ID_TALYN: wil->hw_name = "Talyn"; wil->hw_version = HW_VER_TALYN; memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping)); wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE; wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE; if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) & BIT_NO_FLASH_INDICATION) set_bit(hw_capa_no_flash, wil->hw_capa); break; default: wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n", jtag_id, chip_revision); wil->hw_name = "Unknown"; wil->hw_version = HW_VER_UNKNOWN; return -EINVAL; } iccm_section = wil_find_fw_mapping("fw_code"); if (!iccm_section) { wil_err(wil, "fw_code section not found in fw_mapping\n"); return -EINVAL; } wil->iccm_base = iccm_section->host; wil_info(wil, "Board hardware is %s\n", wil->hw_name); wil_info(wil, "Board hardware is %s, flash %sexist\n", wil->hw_name, test_bit(hw_capa_no_flash, wil->hw_capa) ? "doesn't " : ""); /* Get platform capabilities */ if (wil->platform_ops.get_capa) { Loading @@ -96,6 +121,8 @@ void wil_set_capabilities(struct wil6210_priv *wil) /* extract FW capabilities from file without loading the FW */ wil_request_firmware(wil, wil->wil_fw_name, false); wil_refresh_fw_capabilities(wil); return 0; } void wil_disable_irq(struct wil6210_priv *wil) Loading Loading @@ -299,7 +326,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* rollback to err_iounmap */ wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr); wil_set_capabilities(wil); rc = wil_set_capabilities(wil); if (rc) { wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc); goto err_iounmap; } wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ Loading Loading @@ -385,6 +416,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) static const struct pci_device_id wil6210_pcie_ids[] = { { PCI_DEVICE(0x1ae9, 0x0310) }, { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ { PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */ { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); Loading drivers/net/wireless/ath/wil6210/wil6210.h +45 −6 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -170,6 +171,7 @@ struct RGF_ICR { #define HW_MACHINE_BOOT_DONE (0x3fffffd) #define RGF_USER_USER_CPU_0 (0x8801e0) #define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */ #define RGF_USER_CPU_PC (0x8801e8) #define RGF_USER_MAC_CPU_0 (0x8801fc) #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) Loading @@ -195,6 +197,19 @@ struct RGF_ICR { #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c) #define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */ #define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2) #define RGF_USER_OTP_HW_RD_MACHINE_1 (0x880ce0) #define BIT_NO_FLASH_INDICATION BIT(8) #define RGF_USER_XPM_IFC_RD_TIME1 (0x880cec) #define RGF_USER_XPM_IFC_RD_TIME2 (0x880cf0) #define RGF_USER_XPM_IFC_RD_TIME3 (0x880cf4) #define RGF_USER_XPM_IFC_RD_TIME4 (0x880cf8) #define RGF_USER_XPM_IFC_RD_TIME5 (0x880cfc) #define RGF_USER_XPM_IFC_RD_TIME6 (0x880d00) #define RGF_USER_XPM_IFC_RD_TIME7 (0x880d04) #define RGF_USER_XPM_IFC_RD_TIME8 (0x880d08) #define RGF_USER_XPM_IFC_RD_TIME9 (0x880d0c) #define RGF_USER_XPM_IFC_RD_TIME10 (0x880d10) #define RGF_USER_XPM_RD_DOUT_SAMPLE_TIME (0x880d64) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) Loading Loading @@ -285,22 +300,33 @@ struct RGF_ICR { #define RGF_CAF_PLL_LOCK_STATUS (0x88afec) #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) #define USER_EXT_USER_PMU_3 (0x88d00c) #define BIT_PMU_DEVICE_RDY BIT(0) #define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ #define JTAG_DEV_ID_SPARROW (0x2632072f) #define JTAG_DEV_ID_TALYN (0x7e0e1) #define RGF_USER_REVISION_ID (0x88afe4) #define RGF_USER_REVISION_ID_MASK (3) #define REVISION_ID_SPARROW_B0 (0x0) #define REVISION_ID_SPARROW_D0 (0x3) #define RGF_OTP_MAC (0x8a0620) /* crash codes for FW/Ucode stored here */ #define RGF_FW_ASSERT_CODE (0x91f020) #define RGF_UCODE_ASSERT_CODE (0x91f028) /* ASSERT RGFs */ #define SPARROW_RGF_FW_ASSERT_CODE (0x91f020) #define SPARROW_RGF_UCODE_ASSERT_CODE (0x91f028) #define TALYN_RGF_FW_ASSERT_CODE (0xa37020) #define TALYN_RGF_UCODE_ASSERT_CODE (0xa37028) enum { HW_VER_UNKNOWN, HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */ HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */ HW_VER_TALYN, /* JTAG_DEV_ID_TALYN */ }; /* popular locations */ Loading @@ -316,6 +342,10 @@ enum { #define WIL_DATA_COMPLETION_TO_MS 200 /* Hardware definitions end */ #define SPARROW_FW_MAPPING_TABLE_SIZE 10 #define TALYN_FW_MAPPING_TABLE_SIZE 13 #define MAX_FW_MAPPING_TABLE_SIZE 13 struct fw_map { u32 from; /* linker address - from, inclusive */ u32 to; /* linker address - to, exclusive */ Loading @@ -325,7 +355,9 @@ struct fw_map { }; /* array size should be in sync with actual definition in the wmi.c */ extern const struct fw_map fw_mapping[10]; extern const struct fw_map sparrow_fw_mapping[SPARROW_FW_MAPPING_TABLE_SIZE]; extern const struct fw_map talyn_fw_mapping[TALYN_FW_MAPPING_TABLE_SIZE]; extern struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE]; /** * mk_cidxtid - construct @cidxtid field Loading Loading @@ -572,7 +604,8 @@ enum { }; enum { hw_capability_last hw_capa_no_flash, hw_capa_last }; struct wil_probe_client_req { Loading Loading @@ -648,7 +681,8 @@ struct wil6210_priv { u8 chip_revision; const char *hw_name; const char *wil_fw_name; DECLARE_BITMAP(hw_capabilities, hw_capability_last); char *board_file; DECLARE_BITMAP(hw_capa, hw_capa_last); DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX); DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX); u8 n_mids; /* number of additional MIDs as reported by FW */ Loading Loading @@ -722,7 +756,7 @@ struct wil6210_priv { atomic_t isr_count_rx, isr_count_tx; /* debugfs */ struct dentry *debug; struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; struct wil_blob_wrapper blobs[MAX_FW_MAPPING_TABLE_SIZE]; u8 discovery_mode; u8 abft_len; u8 wakeup_trigger; Loading Loading @@ -770,6 +804,10 @@ struct wil6210_priv { bool suspend_resp_comp; u32 bus_request_kbps; u32 bus_request_kbps_pre_suspend; u32 rgf_fw_assert_code_addr; u32 rgf_ucode_assert_code_addr; u32 iccm_base; }; #define wil_to_wiphy(i) (i->wdev->wiphy) Loading Loading @@ -895,6 +933,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void wil_set_ethtoolops(struct net_device *ndev); struct fw_map *wil_find_fw_mapping(const char *section); void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); Loading Loading
drivers/net/wireless/ath/wil6210/boot_loader.h +8 −1 Original line number Diff line number Diff line /* Copyright (c) 2015 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -39,7 +40,8 @@ struct bl_dedicated_registers_v1 { /* valid only for version 2 and above */ __le32 bl_assert_code; /* 0x880A58 BL Assert code */ __le32 bl_assert_blink; /* 0x880A5C BL Assert Branch */ __le32 bl_reserved[22]; /* 0x880A60 - 0x880AB4 */ __le32 bl_shutdown_handshake; /* 0x880A60 BL cleaner shutdown */ __le32 bl_reserved[21]; /* 0x880A64 - 0x880AB4 */ __le32 bl_magic_number; /* 0x880AB8 BL Magic number */ } __packed; Loading @@ -58,4 +60,9 @@ struct bl_dedicated_registers_v0 { u8 mac_address[6]; /* 0x880A4c BL mac address */ } __packed; /* bits for bl_shutdown_handshake */ #define BL_SHUTDOWN_HS_GRTD BIT(0) #define BL_SHUTDOWN_HS_RTD BIT(1) #define BL_SHUTDOWN_HS_PROT_VER(x) WIL_GET_BITS(x, 28, 31) #endif /* BOOT_LOADER_EXPORT_H_ */
drivers/net/wireless/ath/wil6210/interrupt.c +4 −2 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -395,8 +396,9 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) wil6210_mask_irq_misc(wil, false); if (isr & ISR_MISC_FW_ERROR) { u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE); u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE); u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr); u32 ucode_assert_code = wil_r(wil, wil->rgf_ucode_assert_code_addr); wil_err(wil, "Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n", Loading
drivers/net/wireless/ath/wil6210/main.c +185 −25 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -642,6 +643,98 @@ void wil_priv_deinit(struct wil6210_priv *wil) destroy_workqueue(wil->wmi_wq); } static void wil_shutdown_bl(struct wil6210_priv *wil) { u32 val; wil_s(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v1, bl_shutdown_handshake), BL_SHUTDOWN_HS_GRTD); usleep_range(100, 150); val = wil_r(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v1, bl_shutdown_handshake)); if (val & BL_SHUTDOWN_HS_RTD) { wil_dbg_misc(wil, "BL is ready for halt\n"); return; } wil_err(wil, "BL did not report ready for halt\n"); } /* this format is used by ARC embedded CPU for instruction memory */ static inline u32 ARC_me_imm32(u32 d) { return ((d & 0xffff0000) >> 16) | ((d & 0x0000ffff) << 16); } /* defines access to interrupt vectors for wil_freeze_bl */ #define ARC_IRQ_VECTOR_OFFSET(N) ((N) * 8) /* ARC long jump instruction */ #define ARC_JAL_INST (0x20200f80) static void wil_freeze_bl(struct wil6210_priv *wil) { u32 jal, upc, saved; u32 ivt3 = ARC_IRQ_VECTOR_OFFSET(3); jal = wil_r(wil, wil->iccm_base + ivt3); if (jal != ARC_me_imm32(ARC_JAL_INST)) { wil_dbg_misc(wil, "invalid IVT entry found, skipping\n"); return; } /* prevent the target from entering deep sleep * and disabling memory access */ saved = wil_r(wil, RGF_USER_USAGE_8); wil_w(wil, RGF_USER_USAGE_8, saved | BIT_USER_PREVENT_DEEP_SLEEP); usleep_range(20, 25); /* let the BL process the bit */ /* redirect to endless loop in the INT_L1 context and let it trap */ wil_w(wil, wil->iccm_base + ivt3 + 4, ARC_me_imm32(ivt3)); usleep_range(20, 25); /* let the BL get into the trap */ /* verify the BL is frozen */ upc = wil_r(wil, RGF_USER_CPU_PC); if (upc < ivt3 || (upc > (ivt3 + 8))) wil_dbg_misc(wil, "BL freeze failed, PC=0x%08X\n", upc); wil_w(wil, RGF_USER_USAGE_8, saved); } static void wil_bl_prepare_halt(struct wil6210_priv *wil) { u32 tmp, ver; /* before halting device CPU driver must make sure BL is not accessing * host memory. This is done differently depending on BL version: * 1. For very old BL versions the procedure is skipped * (not supported). * 2. For old BL version we use a special trick to freeze the BL * 3. For new BL versions we shutdown the BL using handshake procedure. */ tmp = wil_r(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, boot_loader_struct_version)); if (!tmp) { wil_dbg_misc(wil, "old BL, skipping halt preperation\n"); return; } tmp = wil_r(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v1, bl_shutdown_handshake)); ver = BL_SHUTDOWN_HS_PROT_VER(tmp); if (ver > 0) wil_shutdown_bl(wil); else wil_freeze_bl(wil); } static inline void wil_halt_cpu(struct wil6210_priv *wil) { wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); Loading Loading @@ -675,7 +768,7 @@ static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode) } } static int wil_target_reset(struct wil6210_priv *wil) static int wil_target_reset(struct wil6210_priv *wil, int no_flash) { int delay = 0; u32 x, x1 = 0; Loading @@ -689,9 +782,16 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); if (!no_flash) { /* clear all boot loader "ready" bits */ wil_w(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); /* this should be safe to write even with old BLs */ wil_w(wil, RGF_USER_BL + offsetof(struct bl_dedicated_registers_v1, bl_shutdown_handshake), 0); } /* Clear Fw Download notification */ wil_c(wil, RGF_USER_USAGE_6, BIT(0)); Loading Loading @@ -732,13 +832,25 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); /* wait until device ready. typical time is 20..80 msec */ if (no_flash) do { msleep(RST_DELAY); x = wil_r(wil, USER_EXT_USER_PMU_3); if (delay++ > RST_COUNT) { wil_err(wil, "Reset not completed, PMU_3 0x%08x\n", x); return -ETIME; } } while ((x & BIT_PMU_DEVICE_RDY) == 0); else do { msleep(RST_DELAY); 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); wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x1 = x; } if (delay++ > RST_COUNT) { Loading @@ -754,6 +866,21 @@ static int wil_target_reset(struct wil6210_priv *wil) 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); if (no_flash) { /* Reset OTP HW vectors to fit 40MHz */ wil_w(wil, RGF_USER_XPM_IFC_RD_TIME1, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME2, 0x20027); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME3, 0x1); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME4, 0x20027); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME5, 0x30003); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME6, 0x20002); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME7, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME8, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME9, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME10, 0x60001); wil_w(wil, RGF_USER_XPM_RD_DOUT_SAMPLE_TIME, 0x57); } wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; } Loading Loading @@ -911,6 +1038,27 @@ static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err) } } static int wil_get_otp_info(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); struct wiphy *wiphy = wil_to_wiphy(wil); u8 mac[8]; wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(RGF_OTP_MAC), sizeof(mac)); if (!is_valid_ether_addr(mac)) { wil_err(wil, "Invalid MAC %pM\n", mac); return -EINVAL; } ether_addr_copy(ndev->perm_addr, mac); ether_addr_copy(wiphy->perm_addr, mac); if (!is_valid_ether_addr(ndev->dev_addr)) ether_addr_copy(ndev->dev_addr, mac); return 0; } static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); Loading Loading @@ -1004,6 +1152,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) { int rc; unsigned long status_flags = BIT(wil_status_resetting); int no_flash; wil_dbg_misc(wil, "reset\n"); Loading Loading @@ -1082,20 +1231,28 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); no_flash = test_bit(hw_capa_no_flash, wil->hw_capa); if (!no_flash) wil_bl_crash_info(wil, false); wil_disable_irq(wil); rc = wil_target_reset(wil); rc = wil_target_reset(wil, no_flash); wil6210_clear_irq(wil); wil_enable_irq(wil); wil_rx_fini(wil); if (rc) { if (!no_flash) wil_bl_crash_info(wil, true); goto out; } if (no_flash) { rc = wil_get_otp_info(wil); } else { rc = wil_get_bl_info(wil); if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ rc = 0; } if (rc) goto out; Loading @@ -1104,6 +1261,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil_info(wil, "Use firmware <%s> + board <%s>\n", wil->wil_fw_name, WIL_BOARD_FILE_NAME); if (!no_flash) wil_bl_prepare_halt(wil); wil_halt_cpu(wil); memset(wil->fw_version, 0, sizeof(wil->fw_version)); /* Loading f/w from the file */ Loading
drivers/net/wireless/ath/wil6210/pcie_bus.c +36 −4 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -39,15 +40,16 @@ static int wil6210_pm_notify(struct notifier_block *notify_block, #endif /* CONFIG_PM */ static void wil_set_capabilities(struct wil6210_priv *wil) int wil_set_capabilities(struct wil6210_priv *wil) { const char *wil_fw_name; u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) & RGF_USER_REVISION_ID_MASK); int platform_capa; struct fw_map *iccm_section; bitmap_zero(wil->hw_capabilities, hw_capability_last); bitmap_zero(wil->hw_capa, hw_capa_last); bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX); bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX); wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT : Loading Loading @@ -75,15 +77,38 @@ void wil_set_capabilities(struct wil6210_priv *wil) wil->hw_version = HW_VER_UNKNOWN; break; } memcpy(fw_mapping, sparrow_fw_mapping, sizeof(sparrow_fw_mapping)); wil->rgf_fw_assert_code_addr = SPARROW_RGF_FW_ASSERT_CODE; wil->rgf_ucode_assert_code_addr = SPARROW_RGF_UCODE_ASSERT_CODE; break; case JTAG_DEV_ID_TALYN: wil->hw_name = "Talyn"; wil->hw_version = HW_VER_TALYN; memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping)); wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE; wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE; if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) & BIT_NO_FLASH_INDICATION) set_bit(hw_capa_no_flash, wil->hw_capa); break; default: wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n", jtag_id, chip_revision); wil->hw_name = "Unknown"; wil->hw_version = HW_VER_UNKNOWN; return -EINVAL; } iccm_section = wil_find_fw_mapping("fw_code"); if (!iccm_section) { wil_err(wil, "fw_code section not found in fw_mapping\n"); return -EINVAL; } wil->iccm_base = iccm_section->host; wil_info(wil, "Board hardware is %s\n", wil->hw_name); wil_info(wil, "Board hardware is %s, flash %sexist\n", wil->hw_name, test_bit(hw_capa_no_flash, wil->hw_capa) ? "doesn't " : ""); /* Get platform capabilities */ if (wil->platform_ops.get_capa) { Loading @@ -96,6 +121,8 @@ void wil_set_capabilities(struct wil6210_priv *wil) /* extract FW capabilities from file without loading the FW */ wil_request_firmware(wil, wil->wil_fw_name, false); wil_refresh_fw_capabilities(wil); return 0; } void wil_disable_irq(struct wil6210_priv *wil) Loading Loading @@ -299,7 +326,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* rollback to err_iounmap */ wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr); wil_set_capabilities(wil); rc = wil_set_capabilities(wil); if (rc) { wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc); goto err_iounmap; } wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ Loading Loading @@ -385,6 +416,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) static const struct pci_device_id wil6210_pcie_ids[] = { { PCI_DEVICE(0x1ae9, 0x0310) }, { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ { PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */ { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); Loading
drivers/net/wireless/ath/wil6210/wil6210.h +45 −6 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -170,6 +171,7 @@ struct RGF_ICR { #define HW_MACHINE_BOOT_DONE (0x3fffffd) #define RGF_USER_USER_CPU_0 (0x8801e0) #define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */ #define RGF_USER_CPU_PC (0x8801e8) #define RGF_USER_MAC_CPU_0 (0x8801fc) #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) Loading @@ -195,6 +197,19 @@ struct RGF_ICR { #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c) #define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */ #define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2) #define RGF_USER_OTP_HW_RD_MACHINE_1 (0x880ce0) #define BIT_NO_FLASH_INDICATION BIT(8) #define RGF_USER_XPM_IFC_RD_TIME1 (0x880cec) #define RGF_USER_XPM_IFC_RD_TIME2 (0x880cf0) #define RGF_USER_XPM_IFC_RD_TIME3 (0x880cf4) #define RGF_USER_XPM_IFC_RD_TIME4 (0x880cf8) #define RGF_USER_XPM_IFC_RD_TIME5 (0x880cfc) #define RGF_USER_XPM_IFC_RD_TIME6 (0x880d00) #define RGF_USER_XPM_IFC_RD_TIME7 (0x880d04) #define RGF_USER_XPM_IFC_RD_TIME8 (0x880d08) #define RGF_USER_XPM_IFC_RD_TIME9 (0x880d0c) #define RGF_USER_XPM_IFC_RD_TIME10 (0x880d10) #define RGF_USER_XPM_RD_DOUT_SAMPLE_TIME (0x880d64) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) Loading Loading @@ -285,22 +300,33 @@ struct RGF_ICR { #define RGF_CAF_PLL_LOCK_STATUS (0x88afec) #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) #define USER_EXT_USER_PMU_3 (0x88d00c) #define BIT_PMU_DEVICE_RDY BIT(0) #define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ #define JTAG_DEV_ID_SPARROW (0x2632072f) #define JTAG_DEV_ID_TALYN (0x7e0e1) #define RGF_USER_REVISION_ID (0x88afe4) #define RGF_USER_REVISION_ID_MASK (3) #define REVISION_ID_SPARROW_B0 (0x0) #define REVISION_ID_SPARROW_D0 (0x3) #define RGF_OTP_MAC (0x8a0620) /* crash codes for FW/Ucode stored here */ #define RGF_FW_ASSERT_CODE (0x91f020) #define RGF_UCODE_ASSERT_CODE (0x91f028) /* ASSERT RGFs */ #define SPARROW_RGF_FW_ASSERT_CODE (0x91f020) #define SPARROW_RGF_UCODE_ASSERT_CODE (0x91f028) #define TALYN_RGF_FW_ASSERT_CODE (0xa37020) #define TALYN_RGF_UCODE_ASSERT_CODE (0xa37028) enum { HW_VER_UNKNOWN, HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */ HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */ HW_VER_TALYN, /* JTAG_DEV_ID_TALYN */ }; /* popular locations */ Loading @@ -316,6 +342,10 @@ enum { #define WIL_DATA_COMPLETION_TO_MS 200 /* Hardware definitions end */ #define SPARROW_FW_MAPPING_TABLE_SIZE 10 #define TALYN_FW_MAPPING_TABLE_SIZE 13 #define MAX_FW_MAPPING_TABLE_SIZE 13 struct fw_map { u32 from; /* linker address - from, inclusive */ u32 to; /* linker address - to, exclusive */ Loading @@ -325,7 +355,9 @@ struct fw_map { }; /* array size should be in sync with actual definition in the wmi.c */ extern const struct fw_map fw_mapping[10]; extern const struct fw_map sparrow_fw_mapping[SPARROW_FW_MAPPING_TABLE_SIZE]; extern const struct fw_map talyn_fw_mapping[TALYN_FW_MAPPING_TABLE_SIZE]; extern struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE]; /** * mk_cidxtid - construct @cidxtid field Loading Loading @@ -572,7 +604,8 @@ enum { }; enum { hw_capability_last hw_capa_no_flash, hw_capa_last }; struct wil_probe_client_req { Loading Loading @@ -648,7 +681,8 @@ struct wil6210_priv { u8 chip_revision; const char *hw_name; const char *wil_fw_name; DECLARE_BITMAP(hw_capabilities, hw_capability_last); char *board_file; DECLARE_BITMAP(hw_capa, hw_capa_last); DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX); DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX); u8 n_mids; /* number of additional MIDs as reported by FW */ Loading Loading @@ -722,7 +756,7 @@ struct wil6210_priv { atomic_t isr_count_rx, isr_count_tx; /* debugfs */ struct dentry *debug; struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; struct wil_blob_wrapper blobs[MAX_FW_MAPPING_TABLE_SIZE]; u8 discovery_mode; u8 abft_len; u8 wakeup_trigger; Loading Loading @@ -770,6 +804,10 @@ struct wil6210_priv { bool suspend_resp_comp; u32 bus_request_kbps; u32 bus_request_kbps_pre_suspend; u32 rgf_fw_assert_code_addr; u32 rgf_ucode_assert_code_addr; u32 iccm_base; }; #define wil_to_wiphy(i) (i->wdev->wiphy) Loading Loading @@ -895,6 +933,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void wil_set_ethtoolops(struct net_device *ndev); struct fw_map *wil_find_fw_mapping(const char *section); void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); Loading