diff options
Diffstat (limited to 'drivers/net/wireless')
144 files changed, 2963 insertions, 8596 deletions
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 71878ab35b93..4d4e2f91e15c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3393,19 +3393,12 @@ static int ath10k_pci_claim(struct ath10k *ar) } /* Target expects 32 bit DMA. Enforce it. */ - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret); goto err_region; } - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n", - ret); - goto err_region; - } - pci_set_master(pdev); /* Arrange for access to Target SoC registers. */ diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 603d2f93ac18..9a224817630a 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1406,11 +1406,6 @@ ath11k_update_per_peer_tx_stats(struct ath11k *ar, * Firmware rate's control to be skipped for this? */ - if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) { - ath11k_warn(ab, "Invalid HE mcs %d peer stats", mcs); - return; - } - if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH11K_HE_MCS_MAX) { ath11k_warn(ab, "Invalid HE mcs %d peer stats", mcs); return; diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 75cc2d80fde8..26c7ae242db6 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -330,6 +330,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) mhi_ctrl->cntrl_dev = ab->dev; mhi_ctrl->fw_image = ab_pci->amss_path; mhi_ctrl->regs = ab->mem; + mhi_ctrl->reg_len = ab->mem_len; ret = ath11k_mhi_get_msi(ab_pci); if (ret) { diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 646ad79f309c..5abb38cc3b55 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -933,20 +933,14 @@ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) goto disable_device; } - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); + ret = dma_set_mask_and_coherent(&pdev->dev, + DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); if (ret) { ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", ATH11K_PCI_DMA_MASK, ret); goto release_region; } - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); - if (ret) { - ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", - ATH11K_PCI_DMA_MASK, ret); - goto release_region; - } - pci_set_master(pdev); ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 43b4ae86e5fb..86b8cb975b1a 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -191,7 +191,7 @@ ath5k_pci_probe(struct pci_dev *pdev, } /* XXX 32-bit addressing only */ - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { dev_err(&pdev->dev, "32-bit DMA not available\n"); goto err_dis; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index b137e7f34397..bd1ef6334997 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2504,8 +2504,10 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) goto free_data_skb; for (index = 0; index < num_pri_streams; index++) { - if (WARN_ON(!data_sync_bufs[index].skb)) + if (WARN_ON(!data_sync_bufs[index].skb)) { + ret = -ENOMEM; goto free_data_skb; + } ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, data_sync_bufs[index]. diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b4885a700296..b0a4ca3559fd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3351,7 +3351,8 @@ found: "Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n", cptr, code, reference, length, major, minor); if ((!AR_SREV_9485(ah) && length >= 1024) || - (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) { + (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485) || + (length > cptr)) { ath_dbg(common, EEPROM, "Skipping bad header\n"); cptr -= COMP_HDR_LEN; continue; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2ca3b86714a9..172081ffe477 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1621,7 +1621,6 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) ath9k_hw_gpio_request_out(ah, i, NULL, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i))); - ath9k_hw_gpio_free(ah, i); } } @@ -2728,14 +2727,17 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type) static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out, const char *label) { + int err; + if (ah->caps.gpio_requested & BIT(gpio)) return; - /* may be requested by BSP, free anyway */ - gpio_free(gpio); - - if (gpio_request_one(gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label)) + err = gpio_request_one(gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label); + if (err) { + ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n", + gpio, err); return; + } ah->caps.gpio_requested |= BIT(gpio); } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index cff9af3af38d..a074e23013c5 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -896,18 +896,12 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (pcim_enable_device(pdev)) return -EIO; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { pr_err("32-bit DMA not available\n"); return ret; } - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - pr_err("32-bit DMA consistent DMA enable failed\n"); - return ret; - } - /* * Cache line size is used to size and align various * structures used to communicate with the hardware. diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index d202f2128df2..ec913ec991f3 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -408,13 +408,14 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n", ch); - if (wcn->sw_scan_opchannel == ch) { + if (wcn->sw_scan_opchannel == ch && wcn->sw_scan_channel) { /* If channel is the initial operating channel, we may * want to receive/transmit regular data packets, then * simply stop the scan session and exit PS mode. */ wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, wcn->sw_scan_vif); + wcn->sw_scan_channel = 0; } else if (wcn->sw_scan) { /* A scan is ongoing, do not change the operating * channel, but start a scan session on the channel. @@ -422,6 +423,7 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN, wcn->sw_scan_vif); wcn36xx_smd_start_scan(wcn, ch); + wcn->sw_scan_channel = ch; } else { wcn36xx_change_opchannel(wcn, ch); } @@ -702,6 +704,7 @@ static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, wcn->sw_scan = true; wcn->sw_scan_vif = vif; + wcn->sw_scan_channel = 0; if (vif_priv->sta_assoc) wcn->sw_scan_opchannel = WCN36XX_HW_CHANNEL(wcn); else @@ -1500,6 +1503,13 @@ static int wcn36xx_probe(struct platform_device *pdev) goto out_wq; } + wcn->nv_file = WLAN_NV_FILE; + ret = of_property_read_string(wcn->dev->parent->of_node, "firmware-name", &wcn->nv_file); + if (ret < 0 && ret != -EINVAL) { + wcn36xx_err("failed to read \"firmware-name\" property: %d\n", ret); + goto out_wq; + } + wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process, hw); if (IS_ERR(wcn->smd_channel)) { wcn36xx_err("failed to open WLAN_CTRL channel\n"); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 0e3be17d8cea..57fa857b290b 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -504,10 +504,10 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn) u16 fm_offset = 0; if (!wcn->nv) { - ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev); + ret = request_firmware(&wcn->nv, wcn->nv_file, wcn->dev); if (ret) { wcn36xx_err("Failed to load nv file %s: %d\n", - WLAN_NV_FILE, ret); + wcn->nv_file, ret); goto out; } } diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 1b831157ede1..cab196bb38cd 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -287,6 +287,10 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) status.rate_idx = 0; } + if (ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) + status.boottime_ns = ktime_get_boottime_ns(); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); if (ieee80211_is_beacon(hdr->frame_control)) { diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 6121d8a5641a..add6e527e833 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -199,6 +199,7 @@ struct wcn36xx { struct device *dev; struct list_head vif_list; + const char *nv_file; const struct firmware *nv; u8 fw_revision; @@ -246,6 +247,7 @@ struct wcn36xx { struct cfg80211_scan_request *scan_req; bool sw_scan; u8 sw_scan_opchannel; + u8 sw_scan_channel; struct ieee80211_vif *sw_scan_vif; struct mutex scan_lock; bool scan_aborted; diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index e481674485c2..29a9f17c2df0 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -11,8 +11,11 @@ #include "wil6210.h" -static int wil_ethtoolops_get_coalesce(struct net_device *ndev, - struct ethtool_coalesce *cp) +static int +wil_ethtoolops_get_coalesce(struct net_device *ndev, + struct ethtool_coalesce *cp, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) { struct wil6210_priv *wil = ndev_to_wil(ndev); u32 tx_itr_en, tx_itr_val = 0; @@ -45,8 +48,11 @@ out: return ret; } -static int wil_ethtoolops_set_coalesce(struct net_device *ndev, - struct ethtool_coalesce *cp) +static int +wil_ethtoolops_set_coalesce(struct net_device *ndev, + struct ethtool_coalesce *cp, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) { struct wil6210_priv *wil = ndev_to_wil(ndev); struct wireless_dev *wdev = ndev->ieee80211_ptr; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile index 9b15bc3f6054..13c13504a6e8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile @@ -23,7 +23,8 @@ brcmfmac-objs += \ feature.o \ btcoex.o \ vendor.o \ - pno.o + pno.o \ + xtlv.o brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \ bcdc.o \ fwsignal.o diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 633d0ab19031..ac02244a6fdf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -128,7 +128,8 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) { /* assign GPIO to SDIO core */ - addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol); + addr = brcmf_chip_enum_base(sdiodev->func1->device); + addr = CORE_CC_REG(addr, gpiocontrol); gpiocontrol = brcmf_sdiod_readl(sdiodev, addr, &ret); gpiocontrol |= 0x2; brcmf_sdiod_writel(sdiodev, addr, gpiocontrol, &ret); @@ -990,6 +991,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index cedba56fc448..f7b96cd69242 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1829,6 +1829,14 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; } break; + case WLAN_AKM_SUITE_FT_OVER_SAE: + val = WPA3_AUTH_SAE_PSK | WPA2_AUTH_FT; + profile->is_ft = true; + if (sme->crypto.sae_pwd) { + brcmf_dbg(INFO, "using SAE offload\n"); + profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; + } + break; default: bphy_err(drvr, "invalid cipher group (%d)\n", sme->crypto.cipher_group); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 45037decba40..1ee49f9e325d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -139,6 +139,8 @@ struct sbconfig { u32 sbidhigh; /* identification */ }; +#define INVALID_RAMBASE ((u32)(~0)) + /* bankidx and bankinfo reg defines corerev >= 8 */ #define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 #define SOCRAM_BANKINFO_SZMASK 0x0000007f @@ -527,7 +529,7 @@ static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) int idx = 1; list_for_each_entry(core, &ci->cores, list) { - brcmf_dbg(INFO, " [%-2d] core 0x%x:%-2d base 0x%08x wrap 0x%08x\n", + brcmf_dbg(INFO, " [%-2d] core 0x%x:%-3d base 0x%08x wrap 0x%08x\n", idx++, core->pub.id, core->pub.rev, core->pub.base, core->wrapbase); @@ -727,11 +729,13 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case BRCM_CC_4364_CHIP_ID: case CY_CC_4373_CHIP_ID: return 0x160000; + case CY_CC_43752_CHIP_ID: + return 0x170000; default: brcmf_err("unknown chip: %s\n", ci->pub.name); break; } - return 0; + return INVALID_RAMBASE; } int brcmf_chip_get_raminfo(struct brcmf_chip *pub) @@ -746,7 +750,7 @@ int brcmf_chip_get_raminfo(struct brcmf_chip *pub) mem_core = container_of(mem, struct brcmf_core_priv, pub); ci->pub.ramsize = brcmf_chip_tcm_ramsize(mem_core); ci->pub.rambase = brcmf_chip_tcm_rambase(ci); - if (!ci->pub.rambase) { + if (ci->pub.rambase == INVALID_RAMBASE) { brcmf_err("RAM base not provided with ARM CR4 core\n"); return -EINVAL; } @@ -757,7 +761,7 @@ int brcmf_chip_get_raminfo(struct brcmf_chip *pub) pub); ci->pub.ramsize = brcmf_chip_sysmem_ramsize(mem_core); ci->pub.rambase = brcmf_chip_tcm_rambase(ci); - if (!ci->pub.rambase) { + if (ci->pub.rambase == INVALID_RAMBASE) { brcmf_err("RAM base not provided with ARM CA7 core\n"); return -EINVAL; } @@ -894,7 +898,8 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) u32 base, wrap; int err; - eromaddr = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, eromptr)); + eromaddr = ci->ops->read32(ci->ctx, + CORE_CC_REG(ci->pub.enum_base, eromptr)); while (desc_type != DMP_DESC_EOT) { val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type); @@ -942,6 +947,11 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) return 0; } +u32 brcmf_chip_enum_base(u16 devid) +{ + return SI_ENUM_BASE_DEFAULT; +} + static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) { struct brcmf_core *core; @@ -954,7 +964,8 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) * For different chiptypes or old sdio hosts w/o chipcommon, * other ways of recognition should be added here. */ - regdata = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, chipid)); + regdata = ci->ops->read32(ci->ctx, + CORE_CC_REG(ci->pub.enum_base, chipid)); ci->pub.chip = regdata & CID_ID_MASK; ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; @@ -974,7 +985,7 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) ci->resetcore = brcmf_chip_sb_resetcore; core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, - SI_ENUM_BASE, 0); + SI_ENUM_BASE_DEFAULT, 0); brcmf_chip_sb_corerev(ci, core); core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, BCM4329_CORE_BUS_BASE, 0); @@ -1088,7 +1099,7 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip) return ret; } -struct brcmf_chip *brcmf_chip_attach(void *ctx, +struct brcmf_chip *brcmf_chip_attach(void *ctx, u16 devid, const struct brcmf_buscore_ops *ops) { struct brcmf_chip_priv *chip; @@ -1113,6 +1124,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, chip->num_cores = 0; chip->ops = ops; chip->ctx = ctx; + chip->pub.enum_base = brcmf_chip_enum_base(devid); err = ops->prepare(ctx); if (err < 0) @@ -1411,6 +1423,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) reg = chip->ops->read32(chip->ctx, addr); return (reg & CC_SR_CTL0_ENABLE_MASK) != 0; case BRCM_CC_4359_CHIP_ID: + case CY_CC_43752_CHIP_ID: case CY_CC_43012_CHIP_ID: addr = CORE_CC_REG(pmu->base, retention_ctl); reg = chip->ops->read32(chip->ctx, addr); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h index 8fa38658e727..d69f101f5834 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h @@ -15,6 +15,7 @@ * * @chip: chip identifier. * @chiprev: chip revision. + * @enum_base: base address of core enumeration space. * @cc_caps: chipcommon core capabilities. * @cc_caps_ext: chipcommon core extended capabilities. * @pmucaps: PMU capabilities. @@ -27,6 +28,7 @@ struct brcmf_chip { u32 chip; u32 chiprev; + u32 enum_base; u32 cc_caps; u32 cc_caps_ext; u32 pmucaps; @@ -70,7 +72,7 @@ struct brcmf_buscore_ops { }; int brcmf_chip_get_raminfo(struct brcmf_chip *pub); -struct brcmf_chip *brcmf_chip_attach(void *ctx, +struct brcmf_chip *brcmf_chip_attach(void *ctx, u16 devid, const struct brcmf_buscore_ops *ops); void brcmf_chip_detach(struct brcmf_chip *chip); struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); @@ -85,5 +87,6 @@ void brcmf_chip_set_passive(struct brcmf_chip *ci); bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec); bool brcmf_chip_sr_capable(struct brcmf_chip *pub); char *brcmf_chip_name(u32 chipid, u32 chiprev, char *buf, uint len); +u32 brcmf_chip_enum_base(u16 devid); #endif /* BRCMF_AXIDMP_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index d40104b8df55..0eb13e5df517 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -431,8 +431,6 @@ struct brcmf_fw { void (*done)(struct device *dev, int err, struct brcmf_fw_request *req); }; -static void brcmf_fw_request_done(const struct firmware *fw, void *ctx); - #ifdef CONFIG_EFI /* In some cases the EFI-var stored nvram contains "ccode=ALL" or "ccode=XV" * to specify "worldwide" compatible settings, but these 2 ccode-s do not work @@ -594,28 +592,47 @@ static int brcmf_fw_complete_request(const struct firmware *fw, return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret; } +static char *brcm_alt_fw_path(const char *path, const char *board_type) +{ + char alt_path[BRCMF_FW_NAME_LEN]; + char suffix[5]; + + strscpy(alt_path, path, BRCMF_FW_NAME_LEN); + /* At least one character + suffix */ + if (strlen(alt_path) < 5) + return NULL; + + /* strip .txt or .bin at the end */ + strscpy(suffix, alt_path + strlen(alt_path) - 4, 5); + alt_path[strlen(alt_path) - 4] = 0; + strlcat(alt_path, ".", BRCMF_FW_NAME_LEN); + strlcat(alt_path, board_type, BRCMF_FW_NAME_LEN); + strlcat(alt_path, suffix, BRCMF_FW_NAME_LEN); + + return kstrdup(alt_path, GFP_KERNEL); +} + static int brcmf_fw_request_firmware(const struct firmware **fw, struct brcmf_fw *fwctx) { struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos]; int ret; - /* nvram files are board-specific, first try a board-specific path */ + /* Files can be board-specific, first try a board-specific path */ if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) { - char alt_path[BRCMF_FW_NAME_LEN]; + char *alt_path; - strlcpy(alt_path, cur->path, BRCMF_FW_NAME_LEN); - /* strip .txt at the end */ - alt_path[strlen(alt_path) - 4] = 0; - strlcat(alt_path, ".", BRCMF_FW_NAME_LEN); - strlcat(alt_path, fwctx->req->board_type, BRCMF_FW_NAME_LEN); - strlcat(alt_path, ".txt", BRCMF_FW_NAME_LEN); + alt_path = brcm_alt_fw_path(cur->path, fwctx->req->board_type); + if (!alt_path) + goto fallback; ret = request_firmware(fw, alt_path, fwctx->dev); + kfree(alt_path); if (ret == 0) return ret; } +fallback: return request_firmware(fw, cur->path, fwctx->dev); } @@ -639,6 +656,22 @@ static void brcmf_fw_request_done(const struct firmware *fw, void *ctx) kfree(fwctx); } +static void brcmf_fw_request_done_alt_path(const struct firmware *fw, void *ctx) +{ + struct brcmf_fw *fwctx = ctx; + struct brcmf_fw_item *first = &fwctx->req->items[0]; + int ret = 0; + + /* Fall back to canonical path if board firmware not found */ + if (!fw) + ret = request_firmware_nowait(THIS_MODULE, true, first->path, + fwctx->dev, GFP_KERNEL, fwctx, + brcmf_fw_request_done); + + if (fw || ret < 0) + brcmf_fw_request_done(fw, ctx); +} + static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req) { struct brcmf_fw_item *item; @@ -660,6 +693,7 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req, { struct brcmf_fw_item *first = &req->items[0]; struct brcmf_fw *fwctx; + char *alt_path; int ret; brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev)); @@ -677,9 +711,18 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req, fwctx->req = req; fwctx->done = fw_cb; - ret = request_firmware_nowait(THIS_MODULE, true, first->path, - fwctx->dev, GFP_KERNEL, fwctx, - brcmf_fw_request_done); + /* First try alternative board-specific path if any */ + alt_path = brcm_alt_fw_path(first->path, fwctx->req->board_type); + if (alt_path) { + ret = request_firmware_nowait(THIS_MODULE, true, alt_path, + fwctx->dev, GFP_KERNEL, fwctx, + brcmf_fw_request_done_alt_path); + kfree(alt_path); + } else { + ret = request_firmware_nowait(THIS_MODULE, true, first->path, + fwctx->dev, GFP_KERNEL, fwctx, + brcmf_fw_request_done); + } if (ret < 0) brcmf_fw_request_done(NULL, fwctx); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index 9ed85420f3ca..d5578ca681bb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -15,6 +15,7 @@ #include "bus.h" #include "debug.h" #include "tracepoint.h" +#include "xtlv.h" #include "fwil.h" #include "proto.h" @@ -150,7 +151,8 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) mutex_lock(&ifp->drvr->proto_block); err = brcmf_fil_cmd_data(ifp, cmd, data, len, false); - brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d, err=%d\n", ifp->ifidx, cmd, + len, err); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); @@ -260,7 +262,8 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, bphy_err(drvr, "Creating iovar failed\n"); } - brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len); + brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d, err=%d\n", ifp->ifidx, name, + len, err); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); @@ -383,14 +386,13 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, err = -EPERM; bphy_err(drvr, "Creating bsscfg failed\n"); } - brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d\n", ifp->ifidx, - ifp->bsscfgidx, name, len); + brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d, err=%d\n", + ifp->ifidx, ifp->bsscfgidx, name, len, err); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); mutex_unlock(&drvr->proto_block); return err; - } s32 @@ -414,3 +416,117 @@ brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data) *data = le32_to_cpu(data_le); return err; } + +static u32 brcmf_create_xtlv(char *name, u16 id, char *data, u32 len, + char *buf, u32 buflen) +{ + u32 iolen; + u32 nmlen; + + nmlen = strlen(name) + 1; + iolen = nmlen + brcmf_xtlv_data_size(len, BRCMF_XTLV_OPTION_ALIGN32); + + if (iolen > buflen) { + brcmf_err("buffer is too short\n"); + return 0; + } + + memcpy(buf, name, nmlen); + brcmf_xtlv_pack_header((void *)(buf + nmlen), id, len, data, + BRCMF_XTLV_OPTION_ALIGN32); + + return iolen; +} + +s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, char *name, u16 id, + void *data, u32 len) +{ + struct brcmf_pub *drvr = ifp->drvr; + s32 err; + u32 buflen; + + mutex_lock(&drvr->proto_block); + + brcmf_dbg(FIL, "ifidx=%d, name=%s, id=%u, len=%u\n", ifp->ifidx, name, + id, len); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); + + buflen = brcmf_create_xtlv(name, id, data, len, + drvr->proto_buf, sizeof(drvr->proto_buf)); + if (buflen) { + err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf, + buflen, true); + } else { + err = -EPERM; + bphy_err(drvr, "Creating xtlv failed\n"); + } + + mutex_unlock(&drvr->proto_block); + return err; +} + +s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, char *name, u16 id, + void *data, u32 len) +{ + struct brcmf_pub *drvr = ifp->drvr; + s32 err; + u32 buflen; + + mutex_lock(&drvr->proto_block); + + buflen = brcmf_create_xtlv(name, id, data, len, + drvr->proto_buf, sizeof(drvr->proto_buf)); + if (buflen) { + err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf, + buflen, false); + if (err == 0) + memcpy(data, drvr->proto_buf, len); + } else { + err = -EPERM; + bphy_err(drvr, "Creating bsscfg failed\n"); + } + brcmf_dbg(FIL, "ifidx=%d, name=%s, id=%u, len=%u, err=%d\n", + ifp->ifidx, name, id, len, err); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); + + mutex_unlock(&drvr->proto_block); + return err; +} + +s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, char *name, u16 id, u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le, + sizeof(data_le)); +} + +s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, char *name, u16 id, u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} + +s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, char *name, u16 id, u8 *data) +{ + return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data)); +} + +s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, char *name, u16 id, u16 *data) +{ + __le16 data_le = cpu_to_le16(*data); + s32 err; + + err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); + if (err == 0) + *data = le16_to_cpu(data_le); + return err; +} + diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h index ae4cf4372908..cb26f8c59c21 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h @@ -97,5 +97,13 @@ s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, void *data, u32 len); s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data); s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data); +s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, char *name, u16 id, + void *data, u32 len); +s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, char *name, u16 id, + void *data, u32 len); +s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, char *name, u16 id, u32 data); +s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, char *name, u16 id, u32 *data); +s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, char *name, u16 id, u8 *data); +s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, char *name, u16 id, u16 *data); #endif /* _fwil_h_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index c49dd0c36ae4..8b149996fc00 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1886,7 +1886,8 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) devinfo->pdev = pdev; pcie_bus_dev = NULL; - devinfo->ci = brcmf_chip_attach(devinfo, &brcmf_pcie_buscore_ops); + devinfo->ci = brcmf_chip_attach(devinfo, pdev->device, + &brcmf_pcie_buscore_ops); if (IS_ERR(devinfo->ci)) { ret = PTR_ERR(devinfo->ci); devinfo->ci = NULL; @@ -2075,7 +2076,7 @@ cleanup: err = brcmf_pcie_probe(pdev, NULL); if (err) - brcmf_err(bus, "probe after resume failed, err=%d\n", err); + __brcmf_err(NULL, __func__, "probe after resume failed, err=%d\n", err); return err; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 97ee9e2e2e35..8effeb7a7269 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -617,6 +617,7 @@ BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio"); /* Note the names are not postfixed with a1 for backward compatibility */ BRCMF_FW_CLM_DEF(43430A1, "brcmfmac43430-sdio"); +BRCMF_FW_DEF(43430B0, "brcmfmac43430b0-sdio"); BRCMF_FW_CLM_DEF(43455, "brcmfmac43455-sdio"); BRCMF_FW_DEF(43456, "brcmfmac43456-sdio"); BRCMF_FW_CLM_DEF(4354, "brcmfmac4354-sdio"); @@ -624,11 +625,15 @@ BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-sdio"); BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); BRCMF_FW_CLM_DEF(4373, "brcmfmac4373-sdio"); BRCMF_FW_CLM_DEF(43012, "brcmfmac43012-sdio"); +BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-sdio"); /* firmware config files */ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt"); MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt"); +/* per-board firmware binaries */ +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.bin"); + static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), @@ -643,14 +648,16 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), - BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), + BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000002, 43430A1), + BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFC, 43430B0), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0x00000200, 43456), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455), BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373), - BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) + BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012), + BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752) }; #define TXCTL_CREDITS 2 @@ -3416,7 +3423,8 @@ err: static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus) { - if (bus->ci->chip == CY_CC_43012_CHIP_ID) + if (bus->ci->chip == CY_CC_43012_CHIP_ID || + bus->ci->chip == CY_CC_43752_CHIP_ID) return true; else return false; @@ -3907,7 +3915,7 @@ static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr) * It can be identified as 4339 by looking at the chip revision. It * is corrected here so the chip.c module has the right info. */ - if (addr == CORE_CC_REG(SI_ENUM_BASE, chipid) && + if (addr == CORE_CC_REG(SI_ENUM_BASE_DEFAULT, chipid) && (sdiodev->func1->device == SDIO_DEVICE_ID_BROADCOM_4339 || sdiodev->func1->device == SDIO_DEVICE_ID_BROADCOM_4335_4339)) { rev = (val & CID_REV_MASK) >> CID_REV_SHIFT; @@ -3943,12 +3951,15 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) int reg_addr; u32 reg_val; u32 drivestrength; + u32 enum_base; sdiodev = bus->sdiodev; sdio_claim_host(sdiodev->func1); - pr_debug("F1 signature read @0x18000000=0x%4x\n", - brcmf_sdiod_readl(sdiodev, SI_ENUM_BASE, NULL)); + enum_base = brcmf_chip_enum_base(sdiodev->func1->device); + + pr_debug("F1 signature read @0x%08x=0x%4x\n", enum_base, + brcmf_sdiod_readl(sdiodev, enum_base, NULL)); /* * Force PLL off until brcmf_chip_attach() @@ -3967,7 +3978,8 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) goto fail; } - bus->ci = brcmf_chip_attach(sdiodev, &brcmf_sdio_buscore_ops); + bus->ci = brcmf_chip_attach(sdiodev, sdiodev->func1->device, + &brcmf_sdio_buscore_ops); if (IS_ERR(bus->ci)) { brcmf_err("brcmf_chip_attach failed!\n"); bus->ci = NULL; @@ -4257,6 +4269,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, switch (sdiod->func1->device) { case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373: + case SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752: brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", CY_4373_F2_WATERMARK); brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, @@ -4442,7 +4455,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->tx_seq = SDPCM_SEQ_WRAP - 1; /* single-threaded workqueue */ - wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM, + wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM | WQ_HIGHPRI, dev_name(&sdiodev->func1->dev)); if (!wq) { brcmf_err("insufficient memory to create txworkqueue\n"); @@ -4616,4 +4629,3 @@ int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep) return ret; } - diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.c new file mode 100644 index 000000000000..2f3c451148db --- /dev/null +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2019 Broadcom + */ + +#include <asm/unaligned.h> +#include <linux/string.h> +#include <linux/bug.h> + +#include "xtlv.h" + +static int brcmf_xtlv_header_size(u16 opts) +{ + int len = (int)offsetof(struct brcmf_xtlv, data); + + if (opts & BRCMF_XTLV_OPTION_IDU8) + --len; + if (opts & BRCMF_XTLV_OPTION_LENU8) + --len; + + return len; +} + +int brcmf_xtlv_data_size(int dlen, u16 opts) +{ + int hsz; + + hsz = brcmf_xtlv_header_size(opts); + if (opts & BRCMF_XTLV_OPTION_ALIGN32) + return roundup(dlen + hsz, 4); + + return dlen + hsz; +} + +void brcmf_xtlv_pack_header(struct brcmf_xtlv *xtlv, u16 id, u16 len, + const u8 *data, u16 opts) +{ + u8 *data_buf; + u16 mask = BRCMF_XTLV_OPTION_IDU8 | BRCMF_XTLV_OPTION_LENU8; + + if (!(opts & mask)) { + u8 *idp = (u8 *)xtlv; + u8 *lenp = idp + sizeof(xtlv->id); + + put_unaligned_le16(id, idp); + put_unaligned_le16(len, lenp); + data_buf = lenp + sizeof(u16); + } else if ((opts & mask) == mask) { /* u8 id and u8 len */ + u8 *idp = (u8 *)xtlv; + u8 *lenp = idp + 1; + + *idp = (u8)id; + *lenp = (u8)len; + data_buf = lenp + sizeof(u8); + } else if (opts & BRCMF_XTLV_OPTION_IDU8) { /* u8 id, u16 len */ + u8 *idp = (u8 *)xtlv; + u8 *lenp = idp + 1; + + *idp = (u8)id; + put_unaligned_le16(len, lenp); + data_buf = lenp + sizeof(u16); + } else if (opts & BRCMF_XTLV_OPTION_LENU8) { /* u16 id, u8 len */ + u8 *idp = (u8 *)xtlv; + u8 *lenp = idp + sizeof(u16); + + put_unaligned_le16(id, idp); + *lenp = (u8)len; + data_buf = lenp + sizeof(u8); + } else { + WARN(true, "Unexpected xtlv option"); + return; + } + + if (opts & BRCMF_XTLV_OPTION_LENU8) { + WARN_ON(len > 0x00ff); + len &= 0xff; + } + + if (data) + memcpy(data_buf, data, len); +} + diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.h new file mode 100644 index 000000000000..e1930ce1b642 --- /dev/null +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2019 Broadcom + */ +#ifndef __BRCMF_XTLV_H +#define __BRCMF_XTLV_H + +#include <linux/types.h> +#include <linux/bits.h> + +/* bcm type(id), length, value with w/16 bit id/len. The structure below + * is nominal, and is used to support variable length id and type. See + * xtlv options below. + */ +struct brcmf_xtlv { + u16 id; + u16 len; + u8 data[0]; +}; + +enum brcmf_xtlv_option { + BRCMF_XTLV_OPTION_ALIGN32 = BIT(0), + BRCMF_XTLV_OPTION_IDU8 = BIT(1), + BRCMF_XTLV_OPTION_LENU8 = BIT(2), +}; + +int brcmf_xtlv_data_size(int dlen, u16 opts); +void brcmf_xtlv_pack_header(struct brcmf_xtlv *xtlv, u16 id, u16 len, + const u8 *data, u16 opts); + +#endif /* __BRCMF_XTLV_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index 26de1bd7fee9..8ddfc3d06687 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -704,7 +704,7 @@ static void brcms_c_write_inits(struct brcms_hardware *wlc_hw, static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs) { u8 idx; - u16 addr[] = { + static const u16 addr[] = { M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4, M_HOST_FLAGS5 }; diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 00309b272a0e..9d81320164ce 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -52,6 +52,7 @@ #define BRCM_CC_4371_CHIP_ID 0x4371 #define CY_CC_4373_CHIP_ID 0x4373 #define CY_CC_43012_CHIP_ID 43012 +#define CY_CC_43752_CHIP_ID 43752 /* USB Device IDs */ #define BRCM_USB_43143_DEVICE_ID 0xbd1e diff --git a/drivers/net/wireless/broadcom/brcm80211/include/soc.h b/drivers/net/wireless/broadcom/brcm80211/include/soc.h index 92d942b44f2c..824921191366 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/soc.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/soc.h @@ -6,7 +6,7 @@ #ifndef _BRCM_SOC_H #define _BRCM_SOC_H -#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ +#define SI_ENUM_BASE_DEFAULT 0x18000000 /* Common core control flags */ #define SICF_BIST_EN 0x8000 diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index fd37d4d2983b..65dd8cff1b01 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -1144,7 +1144,7 @@ static int waitbusy(struct airo_info *ai); static irqreturn_t airo_interrupt(int irq, void* dev_id); static int airo_thread(void *data); static void timer_func(struct net_device *dev); -static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *, int cmd); static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev); #ifdef CISCO_EXT static int readrids(struct net_device *dev, aironet_ioctl *comp); @@ -2664,7 +2664,7 @@ static const struct net_device_ops airo11_netdev_ops = { .ndo_start_xmit = airo_start_xmit11, .ndo_get_stats = airo_get_stats, .ndo_set_mac_address = airo_set_mac_address, - .ndo_do_ioctl = airo_ioctl, + .ndo_siocdevprivate = airo_siocdevprivate, }; static void wifi_setup(struct net_device *dev) @@ -2764,7 +2764,7 @@ static const struct net_device_ops airo_netdev_ops = { .ndo_get_stats = airo_get_stats, .ndo_set_rx_mode = airo_set_multicast_list, .ndo_set_mac_address = airo_set_mac_address, - .ndo_do_ioctl = airo_ioctl, + .ndo_siocdevprivate = airo_siocdevprivate, .ndo_validate_addr = eth_validate_addr, }; @@ -2775,7 +2775,7 @@ static const struct net_device_ops mpi_netdev_ops = { .ndo_get_stats = airo_get_stats, .ndo_set_rx_mode = airo_set_multicast_list, .ndo_set_mac_address = airo_set_mac_address, - .ndo_do_ioctl = airo_ioctl, + .ndo_siocdevprivate = airo_siocdevprivate, .ndo_validate_addr = eth_validate_addr, }; @@ -7661,7 +7661,8 @@ static const struct iw_handler_def airo_handler_def = * Javier Achirica did a great job of merging code from the unnamed CISCO * developer that added support for flashing the card. */ -static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, + void __user *data, int cmd) { int rc = 0; struct airo_info *ai = dev->ml_priv; @@ -7678,7 +7679,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int val = AIROMAGIC; aironet_ioctl com; - if (copy_from_user(&com, rq->ifr_data, sizeof(com))) + if (copy_from_user(&com, data, sizeof(com))) rc = -EFAULT; else if (copy_to_user(com.data, (char *)&val, sizeof(val))) rc = -EFAULT; @@ -7694,7 +7695,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) */ { aironet_ioctl com; - if (copy_from_user(&com, rq->ifr_data, sizeof(com))) { + if (copy_from_user(&com, data, sizeof(com))) { rc = -EFAULT; break; } diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index 5a2a723e480b..7a684b76f39b 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -927,7 +927,8 @@ static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; static int libipw_verify_qos_info(struct libipw_qos_information_element *info_element, int sub_type) { - + if (info_element->elementID != QOS_ELEMENT_ID) + return -1; if (info_element->qui_subtype != sub_type) return -1; if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) @@ -943,57 +944,34 @@ static int libipw_verify_qos_info(struct libipw_qos_information_element /* * Parse a QoS parameter element */ -static int libipw_read_qos_param_element(struct libipw_qos_parameter_info - *element_param, struct libipw_info_element - *info_element) +static int libipw_read_qos_param_element( + struct libipw_qos_parameter_info *element_param, + struct libipw_info_element *info_element) { - int ret = 0; - u16 size = sizeof(struct libipw_qos_parameter_info) - 2; + size_t size = sizeof(*element_param); - if ((info_element == NULL) || (element_param == NULL)) + if (!element_param || !info_element || info_element->len != size - 2) return -1; - if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) { - memcpy(element_param->info_element.qui, info_element->data, - info_element->len); - element_param->info_element.elementID = info_element->id; - element_param->info_element.length = info_element->len; - } else - ret = -1; - if (ret == 0) - ret = libipw_verify_qos_info(&element_param->info_element, - QOS_OUI_PARAM_SUB_TYPE); - return ret; + memcpy(element_param, info_element, size); + return libipw_verify_qos_info(&element_param->info_element, + QOS_OUI_PARAM_SUB_TYPE); } /* * Parse a QoS information element */ -static int libipw_read_qos_info_element(struct - libipw_qos_information_element - *element_info, struct libipw_info_element - *info_element) +static int libipw_read_qos_info_element( + struct libipw_qos_information_element *element_info, + struct libipw_info_element *info_element) { - int ret = 0; - u16 size = sizeof(struct libipw_qos_information_element) - 2; + size_t size = sizeof(struct libipw_qos_information_element) - 2; - if (element_info == NULL) + if (!element_info || !info_element || info_element->len != size - 2) return -1; - if (info_element == NULL) - return -1; - - if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) { - memcpy(element_info->qui, info_element->data, - info_element->len); - element_info->elementID = info_element->id; - element_info->length = info_element->len; - } else - ret = -1; - if (ret == 0) - ret = libipw_verify_qos_info(element_info, - QOS_OUI_INFO_SUB_TYPE); - return ret; + memcpy(element_info, info_element, size); + return libipw_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE); } /* diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index d9baa2fa603b..36d1e6b2568d 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -179,8 +179,8 @@ static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size, { struct libipw_txb *txb; int i; - txb = kmalloc(sizeof(struct libipw_txb) + (sizeof(u8 *) * nr_frags), - gfp_mask); + + txb = kmalloc(struct_size(txb, fragments, nr_frags), gfp_mask); if (!txb) return NULL; diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 6ff2674f8466..45abb25b65a9 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -571,20 +571,18 @@ il3945_tx_skb(struct il_priv *il, /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = - pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, - PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) + txcmd_phys = dma_map_single(&il->pci_dev->dev, &out_cmd->hdr, firstlen, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, txcmd_phys))) goto drop_unlock; /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ secondlen = skb->len - hdr_len; if (secondlen > 0) { - phys_addr = - pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, - PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) + phys_addr = dma_map_single(&il->pci_dev->dev, skb->data + hdr_len, + secondlen, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, phys_addr))) goto drop_unlock; } @@ -1015,11 +1013,11 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority) /* Get physical address of RB/SKB */ page_dma = - pci_map_page(il->pci_dev, page, 0, + dma_map_page(&il->pci_dev->dev, page, 0, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) { + if (unlikely(dma_mapping_error(&il->pci_dev->dev, page_dma))) { __free_pages(page, il->hw_params.rx_page_order); break; } @@ -1028,9 +1026,9 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority) if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - pci_unmap_page(il->pci_dev, page_dma, + dma_unmap_page(&il->pci_dev->dev, page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __free_pages(page, il->hw_params.rx_page_order); return; } @@ -1062,9 +1060,10 @@ il3945_rx_queue_reset(struct il_priv *il, struct il_rx_queue *rxq) /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].page != NULL) { - pci_unmap_page(il->pci_dev, rxq->pool[i].page_dma, + dma_unmap_page(&il->pci_dev->dev, + rxq->pool[i].page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __il_free_pages(il, rxq->pool[i].page); rxq->pool[i].page = NULL; } @@ -1111,9 +1110,10 @@ il3945_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq) int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { if (rxq->pool[i].page != NULL) { - pci_unmap_page(il->pci_dev, rxq->pool[i].page_dma, + dma_unmap_page(&il->pci_dev->dev, + rxq->pool[i].page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __il_free_pages(il, rxq->pool[i].page); rxq->pool[i].page = NULL; } @@ -1213,9 +1213,9 @@ il3945_rx_handle(struct il_priv *il) rxq->queue[i] = NULL; - pci_unmap_page(il->pci_dev, rxb->page_dma, + dma_unmap_page(&il->pci_dev->dev, rxb->page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); pkt = rxb_addr(rxb); len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; @@ -1260,11 +1260,11 @@ il3945_rx_handle(struct il_priv *il) spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { rxb->page_dma = - pci_map_page(il->pci_dev, rxb->page, 0, - PAGE_SIZE << il->hw_params. - rx_page_order, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, - rxb->page_dma))) { + dma_map_page(&il->pci_dev->dev, rxb->page, 0, + PAGE_SIZE << il->hw_params.rx_page_order, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, + rxb->page_dma))) { __il_free_pages(il, rxb->page); rxb->page = NULL; list_add_tail(&rxb->list, &rxq->rx_used); @@ -3616,9 +3616,7 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) { IL_WARN("No suitable DMA available.\n"); goto out_pci_disable_device; diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c index 0597d828bee1..a773939b8c2a 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.c +++ b/drivers/net/wireless/intel/iwlegacy/3945.c @@ -652,16 +652,16 @@ il3945_hw_txq_free_tfd(struct il_priv *il, struct il_tx_queue *txq) /* Unmap tx_cmd */ if (counter) - pci_unmap_single(dev, dma_unmap_addr(&txq->meta[idx], mapping), + dma_unmap_single(&dev->dev, + dma_unmap_addr(&txq->meta[idx], mapping), dma_unmap_len(&txq->meta[idx], len), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); /* unmap chunks if any */ for (i = 1; i < counter; i++) - pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr), - le32_to_cpu(tfd->tbs[i].len), - PCI_DMA_TODEVICE); + dma_unmap_single(&dev->dev, le32_to_cpu(tfd->tbs[i].addr), + le32_to_cpu(tfd->tbs[i].len), DMA_TO_DEVICE); /* free SKB */ if (txq->skbs) { diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 341d6a2bc690..0223532fd56a 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -94,9 +94,10 @@ il4965_rx_queue_reset(struct il_priv *il, struct il_rx_queue *rxq) /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].page != NULL) { - pci_unmap_page(il->pci_dev, rxq->pool[i].page_dma, + dma_unmap_page(&il->pci_dev->dev, + rxq->pool[i].page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __il_free_pages(il, rxq->pool[i].page); rxq->pool[i].page = NULL; } @@ -342,11 +343,10 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority) } /* Get physical address of the RB */ - page_dma = - pci_map_page(il->pci_dev, page, 0, - PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) { + page_dma = dma_map_page(&il->pci_dev->dev, page, 0, + PAGE_SIZE << il->hw_params.rx_page_order, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, page_dma))) { __free_pages(page, il->hw_params.rx_page_order); break; } @@ -355,9 +355,9 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority) if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - pci_unmap_page(il->pci_dev, page_dma, + dma_unmap_page(&il->pci_dev->dev, page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __free_pages(page, il->hw_params.rx_page_order); return; } @@ -409,9 +409,10 @@ il4965_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq) int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { if (rxq->pool[i].page != NULL) { - pci_unmap_page(il->pci_dev, rxq->pool[i].page_dma, + dma_unmap_page(&il->pci_dev->dev, + rxq->pool[i].page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); __il_free_pages(il, rxq->pool[i].page); rxq->pool[i].page = NULL; } @@ -1815,20 +1816,18 @@ il4965_tx_skb(struct il_priv *il, /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = - pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, - PCI_DMA_BIDIRECTIONAL); - if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) + txcmd_phys = dma_map_single(&il->pci_dev->dev, &out_cmd->hdr, firstlen, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, txcmd_phys))) goto drop_unlock; /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ secondlen = skb->len - hdr_len; if (secondlen > 0) { - phys_addr = - pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, - PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) + phys_addr = dma_map_single(&il->pci_dev->dev, skb->data + hdr_len, + secondlen, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, phys_addr))) goto drop_unlock; } @@ -1853,8 +1852,8 @@ il4965_tx_skb(struct il_priv *il, offsetof(struct il_tx_cmd, scratch); /* take back ownership of DMA buffer to enable update */ - pci_dma_sync_single_for_cpu(il->pci_dev, txcmd_phys, firstlen, - PCI_DMA_BIDIRECTIONAL); + dma_sync_single_for_cpu(&il->pci_dev->dev, txcmd_phys, firstlen, + DMA_BIDIRECTIONAL); tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys); @@ -1869,8 +1868,8 @@ il4965_tx_skb(struct il_priv *il, if (info->flags & IEEE80211_TX_CTL_AMPDU) il->ops->txq_update_byte_cnt_tbl(il, txq, le16_to_cpu(tx_cmd->len)); - pci_dma_sync_single_for_device(il->pci_dev, txcmd_phys, firstlen, - PCI_DMA_BIDIRECTIONAL); + dma_sync_single_for_device(&il->pci_dev->dev, txcmd_phys, firstlen, + DMA_BIDIRECTIONAL); /* Tell device the write idx *just past* this latest filled TFD */ q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); @@ -3929,15 +3928,15 @@ il4965_hw_txq_free_tfd(struct il_priv *il, struct il_tx_queue *txq) /* Unmap tx_cmd */ if (num_tbs) - pci_unmap_single(dev, dma_unmap_addr(&txq->meta[idx], mapping), + dma_unmap_single(&dev->dev, + dma_unmap_addr(&txq->meta[idx], mapping), dma_unmap_len(&txq->meta[idx], len), - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); /* Unmap chunks, if any. */ for (i = 1; i < num_tbs; i++) - pci_unmap_single(dev, il4965_tfd_tb_get_addr(tfd, i), - il4965_tfd_tb_get_len(tfd, i), - PCI_DMA_TODEVICE); + dma_unmap_single(&dev->dev, il4965_tfd_tb_get_addr(tfd, i), + il4965_tfd_tb_get_len(tfd, i), DMA_TO_DEVICE); /* free SKB */ if (txq->skbs) { @@ -4243,9 +4242,9 @@ il4965_rx_handle(struct il_priv *il) rxq->queue[i] = NULL; - pci_unmap_page(il->pci_dev, rxb->page_dma, + dma_unmap_page(&il->pci_dev->dev, rxb->page_dma, PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); pkt = rxb_addr(rxb); len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; @@ -4290,12 +4289,12 @@ il4965_rx_handle(struct il_priv *il) spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { rxb->page_dma = - pci_map_page(il->pci_dev, rxb->page, 0, - PAGE_SIZE << il->hw_params. - rx_page_order, PCI_DMA_FROMDEVICE); + dma_map_page(&il->pci_dev->dev, rxb->page, 0, + PAGE_SIZE << il->hw_params.rx_page_order, + DMA_FROM_DEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, - rxb->page_dma))) { + if (unlikely(dma_mapping_error(&il->pci_dev->dev, + rxb->page_dma))) { __il_free_pages(il, rxb->page); rxb->page = NULL; list_add_tail(&rxb->list, &rxq->rx_used); @@ -6514,14 +6513,9 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36)); if (err) { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!err) - err = - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); /* both attempts failed: */ if (err) { IL_WARN("No suitable DMA available.\n"); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 219fed91cac5..683b632981ed 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -2819,10 +2819,10 @@ il_cmd_queue_unmap(struct il_priv *il) i = il_get_cmd_idx(q, q->read_ptr, 0); if (txq->meta[i].flags & CMD_MAPPED) { - pci_unmap_single(il->pci_dev, + dma_unmap_single(&il->pci_dev->dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); txq->meta[i].flags = 0; } @@ -2831,10 +2831,10 @@ il_cmd_queue_unmap(struct il_priv *il) i = q->n_win; if (txq->meta[i].flags & CMD_MAPPED) { - pci_unmap_single(il->pci_dev, + dma_unmap_single(&il->pci_dev->dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); txq->meta[i].flags = 0; } } @@ -3197,10 +3197,9 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) } #endif - phys_addr = - pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size, - PCI_DMA_BIDIRECTIONAL); - if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) { + phys_addr = dma_map_single(&il->pci_dev->dev, &out_cmd->hdr, fix_size, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(&il->pci_dev->dev, phys_addr))) { idx = -ENOMEM; goto out; } @@ -3298,8 +3297,8 @@ il_tx_cmd_complete(struct il_priv *il, struct il_rx_buf *rxb) txq->time_stamp = jiffies; - pci_unmap_single(il->pci_dev, dma_unmap_addr(meta, mapping), - dma_unmap_len(meta, len), PCI_DMA_BIDIRECTIONAL); + dma_unmap_single(&il->pci_dev->dev, dma_unmap_addr(meta, mapping), + dma_unmap_len(meta, len), DMA_BIDIRECTIONAL); /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 7f1faa9d97b4..52d1d391f4c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -9,7 +9,7 @@ #include "iwl-prph.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 64 +#define IWL_22000_UCODE_API_MAX 65 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 @@ -154,7 +154,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .apmg_not_supported = true, \ .trans.mq_rx_supported = true, \ .vht_mu_mimo_supported = true, \ - .mac_addr_from_csr = true, \ + .mac_addr_from_csr = 0x380, \ .ht_params = &iwl_22000_ht_params, \ .nvm_ver = IWL_22000_NVM_VERSION, \ .trans.use_tfh = true, \ @@ -215,6 +215,67 @@ static const struct iwl_ht_params iwl_22000_ht_params = { }, \ } +#define IWL_DEVICE_BZ_COMMON \ + .ucode_api_max = IWL_22000_UCODE_API_MAX, \ + .ucode_api_min = IWL_22000_UCODE_API_MIN, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = 10, \ + .non_shared_ant = ANT_B, \ + .dccm_offset = IWL_22000_DCCM_OFFSET, \ + .dccm_len = IWL_22000_DCCM_LEN, \ + .dccm2_offset = IWL_22000_DCCM2_OFFSET, \ + .dccm2_len = IWL_22000_DCCM2_LEN, \ + .smem_offset = IWL_22000_SMEM_OFFSET, \ + .smem_len = IWL_22000_SMEM_LEN, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .apmg_not_supported = true, \ + .trans.mq_rx_supported = true, \ + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = 0x30, \ + .ht_params = &iwl_22000_ht_params, \ + .nvm_ver = IWL_22000_NVM_VERSION, \ + .trans.use_tfh = true, \ + .trans.rf_id = true, \ + .trans.gen2 = true, \ + .nvm_type = IWL_NVM_EXT, \ + .dbgc_supported = true, \ + .min_umac_error_event_table = 0x400000, \ + .d3_debug_data_base_addr = 0x401000, \ + .d3_debug_data_length = 60 * 1024, \ + .mon_smem_regs = { \ + .write_ptr = { \ + .addr = LDBG_M2S_BUF_WPTR, \ + .mask = LDBG_M2S_BUF_WPTR_VAL_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = LDBG_M2S_BUF_WRAP_CNT, \ + .mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \ + }, \ + } + +#define IWL_DEVICE_BZ \ + IWL_DEVICE_BZ_COMMON, \ + .trans.umac_prph_offset = 0x300000, \ + .trans.device_family = IWL_DEVICE_FAMILY_BZ, \ + .trans.base_params = &iwl_ax210_base_params, \ + .min_txq_size = 128, \ + .gp2_reg_addr = 0xd02c68, \ + .min_256_ba_txq_size = 1024, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = DBGC_DBGBUF_WRAP_AROUND, \ + .mask = 0xffffffff, \ + }, \ + .cur_frag = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ + }, \ + } + const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = { .mq_rx_supported = true, .use_tfh = true, @@ -373,7 +434,7 @@ const struct iwl_cfg_trans_params iwl_ma_trans_cfg = { }; const struct iwl_cfg_trans_params iwl_bz_trans_cfg = { - .device_family = IWL_DEVICE_FAMILY_AX210, + .device_family = IWL_DEVICE_FAMILY_BZ, .base_params = &iwl_ax210_base_params, .mq_rx_supported = true, .use_tfh = true, @@ -394,6 +455,7 @@ const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; +const char iwl_bz_name[] = "Intel(R) TBD Bz device"; const char iwl_ax200_killer_1650w_name[] = "Killer(R) Wi-Fi 6 AX1650w 160MHz Wireless Network Adapter (200D2W)"; @@ -763,28 +825,28 @@ const struct iwl_cfg iwl_cfg_quz_a0_hr_b0 = { const struct iwl_cfg iwl_cfg_bz_a0_hr_b0 = { .fw_name_pre = IWL_BZ_A_HR_B_FW_PRE, .uhb_supported = true, - IWL_DEVICE_AX210, + IWL_DEVICE_BZ, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_bz_a0_gf_a0 = { .fw_name_pre = IWL_BZ_A_GF_A_FW_PRE, .uhb_supported = true, - IWL_DEVICE_AX210, + IWL_DEVICE_BZ, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0 = { .fw_name_pre = IWL_BZ_A_GF4_A_FW_PRE, .uhb_supported = true, - IWL_DEVICE_AX210, + IWL_DEVICE_BZ, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_bz_a0_mr_a0 = { .fw_name_pre = IWL_BZ_A_MR_A_FW_PRE, .uhb_supported = true, - IWL_DEVICE_AX210, + IWL_DEVICE_BZ, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 871533beff30..7a7ca06d46c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -89,7 +89,7 @@ static const struct iwl_tt_params iwl9000_tt_params = { .apmg_not_supported = true, \ .num_rbds = 512, \ .vht_mu_mimo_supported = true, \ - .mac_addr_from_csr = true, \ + .mac_addr_from_csr = 0x380, \ .nvm_type = IWL_NVM_EXT, \ .dbgc_supported = true, \ .min_umac_error_event_table = 0x800000, \ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index c01523f64bfc..cc7b69fd14d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2003 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014, 2018 - 2021 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well @@ -1950,7 +1950,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) } } -static void iwl_nic_error(struct iwl_op_mode *op_mode) +static void iwl_nic_error(struct iwl_op_mode *op_mode, bool sync) { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index 80475c7a6fba..3cd7b423c588 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -318,7 +318,7 @@ iwlagn_accumulative_statistics(struct iwl_priv *priv, (__le32 *)&priv->delta_stats._name, \ (__le32 *)&priv->max_delta_stats._name, \ (__le32 *)&priv->accum_stats._name, \ - sizeof(*_name)); + sizeof(*_name)) ACCUM(common); ACCUM(rx_non_phy); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 34933f133a0a..1efac0b2a94d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -264,7 +264,7 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, goto out_free; } - enabled = !!wifi_pkg->package.elements[0].integer.value; + enabled = !!wifi_pkg->package.elements[1].integer.value; if (!enabled) { *block_list_size = -1; @@ -273,15 +273,15 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, goto out_free; } - if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || - wifi_pkg->package.elements[1].integer.value > + if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER || + wifi_pkg->package.elements[2].integer.value > APCI_WTAS_BLACK_LIST_MAX) { IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", wifi_pkg->package.elements[1].integer.value); ret = -EINVAL; goto out_free; } - *block_list_size = wifi_pkg->package.elements[1].integer.value; + *block_list_size = wifi_pkg->package.elements[2].integer.value; IWL_DEBUG_RADIO(fwrt, "TAS array size %d\n", *block_list_size); if (*block_list_size > APCI_WTAS_BLACK_LIST_MAX) { @@ -294,15 +294,15 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, for (i = 0; i < *block_list_size; i++) { u32 country; - if (wifi_pkg->package.elements[2 + i].type != + if (wifi_pkg->package.elements[3 + i].type != ACPI_TYPE_INTEGER) { IWL_DEBUG_RADIO(fwrt, - "TAS invalid array elem %d\n", 2 + i); + "TAS invalid array elem %d\n", 3 + i); ret = -EINVAL; goto out_free; } - country = wifi_pkg->package.elements[2 + i].integer.value; + country = wifi_pkg->package.elements[3 + i].integer.value; block_list_array[i] = cpu_to_le32(country); IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); } @@ -412,20 +412,35 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); static int iwl_sar_set_profile(union acpi_object *table, struct iwl_sar_profile *profile, - bool enabled) + bool enabled, u8 num_chains, u8 num_sub_bands) { - int i; - - profile->enabled = enabled; - - for (i = 0; i < ACPI_SAR_TABLE_SIZE; i++) { - if (table[i].type != ACPI_TYPE_INTEGER || - table[i].integer.value > U8_MAX) - return -EINVAL; + int i, j, idx = 0; - profile->table[i] = table[i].integer.value; + /* + * The table from ACPI is flat, but we store it in a + * structured array. + */ + for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) { + for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) { + /* if we don't have the values, use the default */ + if (i >= num_chains || j >= num_sub_bands) { + profile->chains[i].subbands[j] = 0; + } else { + if (table[idx].type != ACPI_TYPE_INTEGER || + table[idx].integer.value > U8_MAX) + return -EINVAL; + + profile->chains[i].subbands[j] = + table[idx].integer.value; + + idx++; + } + } } + /* Only if all values were valid can the profile be enabled */ + profile->enabled = enabled; + return 0; } @@ -433,10 +448,10 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, __le16 *per_chain, u32 n_subbands, int prof_a, int prof_b) { - int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; - int i, j, idx; + int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b }; + int i, j; - for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) { + for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) { struct iwl_sar_profile *prof; /* don't allow SAR to be disabled (profile 0 means disable) */ @@ -467,11 +482,10 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, i, profs[i]); IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); for (j = 0; j < n_subbands; j++) { - idx = i * ACPI_SAR_NUM_SUB_BANDS + j; per_chain[i * n_subbands + j] = - cpu_to_le16(prof->table[idx]); + cpu_to_le16(prof->chains[i].subbands[j]); IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", - j, prof->table[idx]); + j, prof->chains[i].subbands[j]); } } @@ -486,7 +500,7 @@ int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, for (i = 0; i < n_tables; i++) { ret = iwl_sar_fill_table(fwrt, - &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAIN_LIMITS], + &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0], n_subbands, prof_a, prof_b); if (ret) break; @@ -501,28 +515,71 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) union acpi_object *wifi_pkg, *table, *data; bool enabled; int ret, tbl_rev; + u8 num_chains, num_sub_bands; data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); if (IS_ERR(data)) return PTR_ERR(data); + /* start by trying to read revision 2 */ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, - ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; + ACPI_WRDS_WIFI_DATA_SIZE_REV2, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV2; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; + + goto read_table; } - if (tbl_rev != 0) { - ret = -EINVAL; - goto out_free; + /* then try revision 1 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV1, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 1) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV1; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; + + goto read_table; + } + + /* then finally revision 0 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV0, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV0; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; + + goto read_table; } + ret = PTR_ERR(wifi_pkg); + goto out_free; + +read_table: if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { ret = -EINVAL; goto out_free; } + IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); + enabled = !!(wifi_pkg->package.elements[1].integer.value); /* position of the actual table */ @@ -531,7 +588,8 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) /* The profile from WRDS is officially profile 1, but goes * into sar_profiles[0] (because we don't have a profile 0). */ - ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled); + ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled, + num_chains, num_sub_bands); out_free: kfree(data); return ret; @@ -544,23 +602,64 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) bool enabled; int i, n_profiles, tbl_rev, pos; int ret = 0; + u8 num_chains, num_sub_bands; data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); if (IS_ERR(data)) return PTR_ERR(data); + /* start by trying to read revision 2 */ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, - ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; + ACPI_EWRD_WIFI_DATA_SIZE_REV2, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV2; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; + + goto read_table; } - if (tbl_rev != 0) { - ret = -EINVAL; - goto out_free; + /* then try revision 1 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_EWRD_WIFI_DATA_SIZE_REV1, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 1) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV1; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; + + goto read_table; + } + + /* then finally revision 0 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_EWRD_WIFI_DATA_SIZE_REV0, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV0; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; + + goto read_table; } + ret = PTR_ERR(wifi_pkg); + goto out_free; + +read_table: if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { ret = -EINVAL; @@ -589,13 +688,13 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) * have profile 0). So in the array we start from 1. */ ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], - &fwrt->sar_profiles[i + 1], - enabled); + &fwrt->sar_profiles[i + 1], enabled, + num_chains, num_sub_bands); if (ret < 0) break; /* go to the next table */ - pos += ACPI_SAR_TABLE_SIZE; + pos += num_chains * num_sub_bands; } out_free: @@ -607,41 +706,93 @@ IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data; - int i, j, ret, tbl_rev; - int idx = 1; + int i, j, k, ret, tbl_rev; + int idx = 1; /* start from one to skip the domain */ + u8 num_bands; data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); if (IS_ERR(data)) return PTR_ERR(data); + /* start by trying to read revision 2 */ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, - ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); + ACPI_WGDS_WIFI_DATA_SIZE_REV2, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; + num_bands = ACPI_GEO_NUM_BANDS_REV2; + + goto read_table; } - if (tbl_rev > 1) { - ret = -EINVAL; - goto out_free; + /* then try revision 0 (which is the same as 1) */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WGDS_WIFI_DATA_SIZE_REV0, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0 && tbl_rev != 1) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_bands = ACPI_GEO_NUM_BANDS_REV0; + + goto read_table; } + ret = PTR_ERR(wifi_pkg); + goto out_free; + +read_table: fwrt->geo_rev = tbl_rev; for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { + for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) { union acpi_object *entry; - entry = &wifi_pkg->package.elements[idx++]; - if (entry->type != ACPI_TYPE_INTEGER || - entry->integer.value > U8_MAX) { - ret = -EINVAL; - goto out_free; + /* + * num_bands is either 2 or 3, if it's only 2 then + * fill the third band (6 GHz) with the values from + * 5 GHz (second band) + */ + if (j >= num_bands) { + fwrt->geo_profiles[i].bands[j].max = + fwrt->geo_profiles[i].bands[1].max; + } else { + entry = &wifi_pkg->package.elements[idx++]; + if (entry->type != ACPI_TYPE_INTEGER || + entry->integer.value > U8_MAX) { + ret = -EINVAL; + goto out_free; + } + + fwrt->geo_profiles[i].bands[j].max = + entry->integer.value; } - fwrt->geo_profiles[i].values[j] = entry->integer.value; + for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { + /* same here as above */ + if (j >= num_bands) { + fwrt->geo_profiles[i].bands[j].chains[k] = + fwrt->geo_profiles[i].bands[1].chains[k]; + } else { + entry = &wifi_pkg->package.elements[idx++]; + if (entry->type != ACPI_TYPE_INTEGER || + entry->integer.value > U8_MAX) { + ret = -EINVAL; + goto out_free; + } + + fwrt->geo_profiles[i].bands[j].chains[k] = + entry->integer.value; + } + } } } + ret = 0; out_free: kfree(data); @@ -673,43 +824,26 @@ IWL_EXPORT_SYMBOL(iwl_sar_geo_support); int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, struct iwl_per_chain_offset *table, u32 n_bands) { - int ret, i, j; + int i, j; if (!iwl_sar_geo_support(fwrt)) return -EOPNOTSUPP; - ret = iwl_sar_get_wgds_table(fwrt); - if (ret < 0) { - IWL_DEBUG_RADIO(fwrt, - "Geo SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* we don't fail if the table is not available */ - return -ENOENT; - } - for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { for (j = 0; j < n_bands; j++) { struct iwl_per_chain_offset *chain = &table[i * n_bands + j]; - u8 *value; - - if (j * ACPI_GEO_PER_CHAIN_SIZE >= - ARRAY_SIZE(fwrt->geo_profiles[0].values)) - /* - * Currently we only store lb an hb values, and - * don't have any special ones for uhb. So leave - * those empty for the time being - */ - break; - - value = &fwrt->geo_profiles[i].values[j * - ACPI_GEO_PER_CHAIN_SIZE]; - chain->max_tx_power = cpu_to_le16(value[0]); - chain->chain_a = value[1]; - chain->chain_b = value[2]; + + chain->max_tx_power = + cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); + chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0]; + chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1]; IWL_DEBUG_RADIO(fwrt, "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", - i, j, value[1], value[2], value[0]); + i, j, + fwrt->geo_profiles[i].bands[j].chains[0], + fwrt->geo_profiles[i].bands[j].chains[1], + fwrt->geo_profiles[i].bands[j].max); } } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index b858e998999c..16ed0995b51e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -26,21 +26,46 @@ #define ACPI_WIFI_DOMAIN (0x07) -#define ACPI_SAR_TABLE_SIZE 10 #define ACPI_SAR_PROFILE_NUM 4 -#define ACPI_GEO_TABLE_SIZE 6 #define ACPI_NUM_GEO_PROFILES 3 #define ACPI_GEO_PER_CHAIN_SIZE 3 -#define ACPI_SAR_NUM_CHAIN_LIMITS 2 -#define ACPI_SAR_NUM_SUB_BANDS 5 -#define ACPI_SAR_NUM_TABLES 1 +#define ACPI_SAR_NUM_CHAINS_REV0 2 +#define ACPI_SAR_NUM_CHAINS_REV1 2 +#define ACPI_SAR_NUM_CHAINS_REV2 4 +#define ACPI_SAR_NUM_SUB_BANDS_REV0 5 +#define ACPI_SAR_NUM_SUB_BANDS_REV1 11 +#define ACPI_SAR_NUM_SUB_BANDS_REV2 11 + +#define ACPI_WRDS_WIFI_DATA_SIZE_REV0 (ACPI_SAR_NUM_CHAINS_REV0 * \ + ACPI_SAR_NUM_SUB_BANDS_REV0 + 2) +#define ACPI_WRDS_WIFI_DATA_SIZE_REV1 (ACPI_SAR_NUM_CHAINS_REV1 * \ + ACPI_SAR_NUM_SUB_BANDS_REV1 + 2) +#define ACPI_WRDS_WIFI_DATA_SIZE_REV2 (ACPI_SAR_NUM_CHAINS_REV2 * \ + ACPI_SAR_NUM_SUB_BANDS_REV2 + 2) +#define ACPI_EWRD_WIFI_DATA_SIZE_REV0 ((ACPI_SAR_PROFILE_NUM - 1) * \ + ACPI_SAR_NUM_CHAINS_REV0 * \ + ACPI_SAR_NUM_SUB_BANDS_REV0 + 3) +#define ACPI_EWRD_WIFI_DATA_SIZE_REV1 ((ACPI_SAR_PROFILE_NUM - 1) * \ + ACPI_SAR_NUM_CHAINS_REV1 * \ + ACPI_SAR_NUM_SUB_BANDS_REV1 + 3) +#define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ + ACPI_SAR_NUM_CHAINS_REV2 * \ + ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) + +/* revision 0 and 1 are identical, except for the semantics in the FW */ +#define ACPI_GEO_NUM_BANDS_REV0 2 +#define ACPI_GEO_NUM_BANDS_REV2 3 +#define ACPI_GEO_NUM_CHAINS 2 + +#define ACPI_WGDS_WIFI_DATA_SIZE_REV0 (ACPI_NUM_GEO_PROFILES * \ + ACPI_GEO_NUM_BANDS_REV0 * \ + ACPI_GEO_PER_CHAIN_SIZE + 1) +#define ACPI_WGDS_WIFI_DATA_SIZE_REV2 (ACPI_NUM_GEO_PROFILES * \ + ACPI_GEO_NUM_BANDS_REV2 * \ + ACPI_GEO_PER_CHAIN_SIZE + 1) -#define ACPI_WRDS_WIFI_DATA_SIZE (ACPI_SAR_TABLE_SIZE + 2) -#define ACPI_EWRD_WIFI_DATA_SIZE ((ACPI_SAR_PROFILE_NUM - 1) * \ - ACPI_SAR_TABLE_SIZE + 3) -#define ACPI_WGDS_WIFI_DATA_SIZE 19 #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 #define ACPI_ECKV_WIFI_DATA_SIZE 2 @@ -51,8 +76,6 @@ #define APCI_WTAS_BLACK_LIST_MAX 16 #define ACPI_WTAS_WIFI_DATA_SIZE (3 + APCI_WTAS_BLACK_LIST_MAX) -#define ACPI_WGDS_TABLE_SIZE 3 - #define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((IWL_NUM_CHAIN_LIMITS * \ IWL_NUM_SUB_BANDS_V1) + 2) #define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \ @@ -64,13 +87,28 @@ #define ACPI_PPAG_MIN_HB -16 #define ACPI_PPAG_MAX_HB 40 +/* + * The profile for revision 2 is a superset of revision 1, which is in + * turn a superset of revision 0. So we can store all revisions + * inside revision 2, which is what we represent here. + */ +struct iwl_sar_profile_chain { + u8 subbands[ACPI_SAR_NUM_SUB_BANDS_REV2]; +}; + struct iwl_sar_profile { bool enabled; - u8 table[ACPI_SAR_TABLE_SIZE]; + struct iwl_sar_profile_chain chains[ACPI_SAR_NUM_CHAINS_REV2]; +}; + +/* Same thing as with SAR, all revisions fit in revision 2 */ +struct iwl_geo_profile_band { + u8 max; + u8 chains[ACPI_GEO_NUM_CHAINS]; }; struct iwl_geo_profile { - u8 values[ACPI_GEO_TABLE_SIZE]; + struct iwl_geo_profile_band bands[ACPI_GEO_NUM_BANDS_REV2]; }; enum iwl_dsm_funcs_rev_0 { @@ -234,7 +272,7 @@ static inline int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) static inline int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) { - return -ENOENT; + return 1; } static inline bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h index 01580c9175f3..3e81e9369224 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h @@ -142,7 +142,7 @@ enum iwl_bt_mxbox_dw3 { "\t%s: %d%s", \ #_field, \ BT_MBOX_MSG(notif, _num, _field), \ - true ? "\n" : ", "); + true ? "\n" : ", ") enum iwl_bt_activity_grading { BT_OFF = 0, BT_ON_NO_CONNECTION = 1, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index ce060c3dfd7b..ee6b5844a871 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -550,7 +550,8 @@ enum iwl_legacy_cmds { WOWLAN_CONFIGURATION = 0xe1, /** - * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd + * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd_v4, + * &struct iwl_wowlan_rsc_tsc_params_cmd */ WOWLAN_TSC_RSC_PARAM = 0xe2, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index b2e7ef3ddc88..3ec82cae3981 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -6,6 +6,7 @@ */ #ifndef __iwl_fw_api_d3_h__ #define __iwl_fw_api_d3_h__ +#include <iwl-trans.h> /** * enum iwl_d0i3_flags - d0i3 flags @@ -389,11 +390,14 @@ struct iwl_wowlan_config_cmd { u8 reserved; } __packed; /* WOWLAN_CONFIG_API_S_VER_5 */ +#define IWL_NUM_RSC 16 +#define WOWLAN_KEY_MAX_SIZE 32 +#define WOWLAN_GTK_KEYS_NUM 2 +#define WOWLAN_IGTK_KEYS_NUM 2 + /* * WOWLAN_TSC_RSC_PARAMS */ -#define IWL_NUM_RSC 16 - struct tkip_sc { __le16 iv16; __le16 pad; @@ -425,11 +429,19 @@ struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 { union iwl_all_tsc_rsc all_tsc_rsc; } __packed; /* ALL_TSC_RSC_API_S_VER_2 */ -struct iwl_wowlan_rsc_tsc_params_cmd { +struct iwl_wowlan_rsc_tsc_params_cmd_v4 { struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 params; __le32 sta_id; } __packed; /* ALL_TSC_RSC_API_S_VER_4 */ +struct iwl_wowlan_rsc_tsc_params_cmd { + __le64 ucast_rsc[IWL_MAX_TID_COUNT]; + __le64 mcast_rsc[WOWLAN_GTK_KEYS_NUM][IWL_MAX_TID_COUNT]; + __le32 sta_id; +#define IWL_MCAST_KEY_MAP_INVALID 0xff + u8 mcast_key_id_map[4]; +} __packed; /* ALL_TSC_RSC_API_S_VER_5 */ + #define IWL_MIC_KEY_SIZE 8 struct iwl_mic_keys { u8 tx[IWL_MIC_KEY_SIZE]; @@ -541,10 +553,6 @@ struct iwl_wowlan_gtk_status_v1 { struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 rsc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */ -#define WOWLAN_KEY_MAX_SIZE 32 -#define WOWLAN_GTK_KEYS_NUM 2 -#define WOWLAN_IGTK_KEYS_NUM 2 - /** * struct iwl_wowlan_gtk_status - GTK status * @key: GTK material diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 5a2d9a1f7e73..d8b5870d6e9a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -33,12 +33,11 @@ struct iwl_fw_ini_hcmd { * * @version: TLV version * @domain: domain of the TLV. One of &enum iwl_fw_ini_dbg_domain - * @data: TLV data */ struct iwl_fw_ini_header { __le32 version; __le32 domain; - u8 data[]; + /* followed by the data */ } __packed; /* FW_TLV_DEBUG_HEADER_S_VER_1 */ /** @@ -130,6 +129,7 @@ struct iwl_fw_ini_region_internal_buffer { * &IWL_FW_INI_REGION_PERIPHERY_PHY, &IWL_FW_INI_REGION_PERIPHERY_AUX, * &IWL_FW_INI_REGION_PAGING, &IWL_FW_INI_REGION_CSR, * &IWL_FW_INI_REGION_DRAM_IMR and &IWL_FW_INI_REGION_PCI_IOSF_CONFIG + * &IWL_FW_INI_REGION_DBGI_SRAM, &FW_TLV_DEBUG_REGION_TYPE_DBGI_SRAM, * @fifos: fifos configuration. Used by &IWL_FW_INI_REGION_TXF and * &IWL_FW_INI_REGION_RXF * @err_table: error table configuration. Used by @@ -249,7 +249,6 @@ struct iwl_fw_ini_hcmd_tlv { * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC2: allocation meant for DBGC2 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC3: allocation meant for DBGC3 configuration - * @IWL_FW_INI_ALLOCATION_ID_INTERNAL: allocation meant for Intreanl SMEM in D3 * @IWL_FW_INI_ALLOCATION_NUM: number of allocation ids */ enum iwl_fw_ini_allocation_id { @@ -257,7 +256,6 @@ enum iwl_fw_ini_allocation_id { IWL_FW_INI_ALLOCATION_ID_DBGC1, IWL_FW_INI_ALLOCATION_ID_DBGC2, IWL_FW_INI_ALLOCATION_ID_DBGC3, - IWL_FW_INI_ALLOCATION_ID_INTERNAL, IWL_FW_INI_ALLOCATION_NUM, }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ @@ -298,6 +296,7 @@ enum iwl_fw_ini_buffer_location { * @IWL_FW_INI_REGION_DRAM_IMR: IMR memory * @IWL_FW_INI_REGION_PCI_IOSF_CONFIG: PCI/IOSF config * @IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY: special device memory + * @IWL_FW_INI_REGION_DBGI_SRAM: periphery registers of DBGI SRAM * @IWL_FW_INI_REGION_NUM: number of region types */ enum iwl_fw_ini_region_type { @@ -319,6 +318,7 @@ enum iwl_fw_ini_region_type { IWL_FW_INI_REGION_DRAM_IMR, IWL_FW_INI_REGION_PCI_IOSF_CONFIG, IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY, + IWL_FW_INI_REGION_DBGI_SRAM, IWL_FW_INI_REGION_NUM }; /* FW_TLV_DEBUG_REGION_TYPE_API_E */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 0e38eb1cd75d..6bbb8b8c91cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #ifndef __iwl_fw_api_location_h__ #define __iwl_fw_api_location_h__ @@ -151,6 +151,10 @@ enum iwl_tof_mcsi_enable { * is valid * @IWL_TOF_RESPONDER_CMD_VALID_NDP_PARAMS: NDP parameters are valid * @IWL_TOF_RESPONDER_CMD_VALID_LMR_FEEDBACK: LMR feedback support is valid + * @IWL_TOF_RESPONDER_CMD_VALID_SESSION_ID: session id flag is valid + * @IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR: the bss_color field is valid + * @IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR: the + * min_time_between_msr and max_time_between_msr fields are valid */ enum iwl_tof_responder_cmd_valid_field { IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO = BIT(0), @@ -169,6 +173,9 @@ enum iwl_tof_responder_cmd_valid_field { IWL_TOF_RESPONDER_CMD_VALID_NDP_SUPPORT = BIT(22), IWL_TOF_RESPONDER_CMD_VALID_NDP_PARAMS = BIT(23), IWL_TOF_RESPONDER_CMD_VALID_LMR_FEEDBACK = BIT(24), + IWL_TOF_RESPONDER_CMD_VALID_SESSION_ID = BIT(25), + IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR = BIT(26), + IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR = BIT(27), }; /** @@ -186,6 +193,8 @@ enum iwl_tof_responder_cmd_valid_field { * @IWL_TOF_RESPONDER_FLAGS_NDP_SUPPORT: support NDP ranging * @IWL_TOF_RESPONDER_FLAGS_LMR_FEEDBACK: request for LMR feedback if the * initiator supports it + * @IWL_TOF_RESPONDER_FLAGS_SESSION_ID: send the session id in the initial FTM + * frame. */ enum iwl_tof_responder_cfg_flags { IWL_TOF_RESPONDER_FLAGS_NON_ASAP_SUPPORT = BIT(0), @@ -200,6 +209,7 @@ enum iwl_tof_responder_cfg_flags { IWL_TOF_RESPONDER_FLAGS_FTM_TX_ANT = RATE_MCS_ANT_ABC_MSK, IWL_TOF_RESPONDER_FLAGS_NDP_SUPPORT = BIT(24), IWL_TOF_RESPONDER_FLAGS_LMR_FEEDBACK = BIT(25), + IWL_TOF_RESPONDER_FLAGS_SESSION_ID = BIT(27), }; /** @@ -297,13 +307,13 @@ struct iwl_tof_responder_config_cmd_v7 { * @r2i_ndp_params: parameters for R2I NDP. * bits 0 - 2: max number of LTF repetitions * bits 3 - 5: max number of spatial streams (supported values are < 2) - * bits 6 - 7: max number of total LTFs - * (&enum ieee80211_range_params_max_total_ltf) + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf * @i2r_ndp_params: parameters for I2R NDP. * bits 0 - 2: max number of LTF repetitions * bits 3 - 5: max number of spatial streams - * bits 6 - 7: max number of total LTFs - * (&enum ieee80211_range_params_max_total_ltf) + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf */ struct iwl_tof_responder_config_cmd_v8 { __le32 cmd_valid_fields; @@ -322,6 +332,58 @@ struct iwl_tof_responder_config_cmd_v8 { u8 i2r_ndp_params; } __packed; /* TOF_RESPONDER_CONFIG_CMD_API_S_VER_8 */ +/** + * struct iwl_tof_responder_config_cmd_v9 - ToF AP mode (for debug) + * @cmd_valid_fields: &iwl_tof_responder_cmd_valid_field + * @responder_cfg_flags: &iwl_tof_responder_cfg_flags + * @format_bw: bits 0 - 3: &enum iwl_location_frame_format. + * bits 4 - 7: &enum iwl_location_bw. + * @bss_color: current AP bss_color + * @channel_num: current AP Channel + * @ctrl_ch_position: coding of the control channel position relative to + * the center frequency, see iwl_mvm_get_ctrl_pos() + * @sta_id: index of the AP STA when in AP mode + * @reserved1: reserved + * @toa_offset: Artificial addition [pSec] for the ToA - to be used for debug + * purposes, simulating station movement by adding various values + * to this field + * @common_calib: XVT: common calibration value + * @specific_calib: XVT: specific calibration value + * @bssid: Current AP BSSID + * @r2i_ndp_params: parameters for R2I NDP. + * bits 0 - 2: max number of LTF repetitions + * bits 3 - 5: max number of spatial streams (supported values are < 2) + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf + * @i2r_ndp_params: parameters for I2R NDP. + * bits 0 - 2: max number of LTF repetitions + * bits 3 - 5: max number of spatial streams + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf + * @min_time_between_msr: for non trigger based NDP ranging, minimum time + * between measurements in milliseconds. + * @max_time_between_msr: for non trigger based NDP ranging, maximum time + * between measurements in milliseconds. + */ +struct iwl_tof_responder_config_cmd_v9 { + __le32 cmd_valid_fields; + __le32 responder_cfg_flags; + u8 format_bw; + u8 bss_color; + u8 channel_num; + u8 ctrl_ch_position; + u8 sta_id; + u8 reserved1; + __le16 toa_offset; + __le16 common_calib; + __le16 specific_calib; + u8 bssid[ETH_ALEN]; + u8 r2i_ndp_params; + u8 i2r_ndp_params; + __le16 min_time_between_msr; + __le16 max_time_between_msr; +} __packed; /* TOF_RESPONDER_CONFIG_CMD_API_S_VER_8 */ + #define IWL_LCI_CIVIC_IE_MAX_SIZE 400 /** @@ -489,6 +551,10 @@ struct iwl_tof_range_req_ap_entry_v2 { * instead of fw internal values. * @IWL_INITIATOR_AP_FLAGS_PMF: request to protect the negotiation and LMR * frames with protected management frames. + * @IWL_INITIATOR_AP_FLAGS_TERMINATE_ON_LMR_FEEDBACK: terminate the session if + * the responder asked for LMR feedback although the initiator did not set + * the LMR feedback bit in the FTM request. If not set, the initiator will + * continue with the session and will provide the LMR feedback. */ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_ASAP = BIT(1), @@ -504,6 +570,7 @@ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_LMR_FEEDBACK = BIT(12), IWL_INITIATOR_AP_FLAGS_USE_CALIB = BIT(13), IWL_INITIATOR_AP_FLAGS_PMF = BIT(14), + IWL_INITIATOR_AP_FLAGS_TERMINATE_ON_LMR_FEEDBACK = BIT(15), }; /** @@ -795,6 +862,90 @@ struct iwl_tof_range_req_ap_entry_v8 { } __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_8 */ /** + * struct iwl_tof_range_req_ap_entry_v9 - AP configuration parameters + * @initiator_ap_flags: see &enum iwl_initiator_ap_flags. + * @channel_num: AP Channel number + * @format_bw: bits 0 - 3: &enum iwl_location_frame_format. + * bits 4 - 7: &enum iwl_location_bw. + * @ctrl_ch_position: Coding of the control channel position relative to the + * center frequency, see iwl_mvm_get_ctrl_pos(). + * @ftmr_max_retries: Max number of retries to send the FTMR in case of no + * reply from the AP. + * @bssid: AP's BSSID + * @burst_period: For EDCA based ranging: Recommended value to be sent to the + * AP. Measurement periodicity In units of 100ms. ignored if + * num_of_bursts_exp = 0. + * For non trigger based NDP ranging, the maximum time between + * measurements in units of milliseconds. + * @samples_per_burst: the number of FTMs pairs in single Burst (1-31); + * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of + * the number of measurement iterations (min 2^0 = 1, max 2^14) + * @sta_id: the station id of the AP. Only relevant when associated to the AP, + * otherwise should be set to &IWL_MVM_INVALID_STA. + * @cipher: pairwise cipher suite for secured measurement. + * &enum iwl_location_cipher. + * @hltk: HLTK to be used for secured 11az measurement + * @tk: TK to be used for secured 11az measurement + * @calib: An array of calibration values per FTM rx bandwidth. + * If &IWL_INITIATOR_AP_FLAGS_USE_CALIB is set, the fw will use the + * calibration value that corresponds to the rx bandwidth of the FTM + * frame. + * @beacon_interval: beacon interval of the AP in TUs. Only required if + * &IWL_INITIATOR_AP_FLAGS_TB is set. + * @bss_color: the BSS color of the responder. Only valid if + * &IWL_INITIATOR_AP_FLAGS_TB or &IWL_INITIATOR_AP_FLAGS_NON_TB is set. + * @rx_pn: the next expected PN for protected management frames Rx. LE byte + * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id + * is set to &IWL_MVM_INVALID_STA. + * @tx_pn: the next PN to use for protected management frames Tx. LE byte + * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id + * is set to &IWL_MVM_INVALID_STA. + * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. + * bits 0 - 2: max LTF repetitions + * bits 3 - 5: max number of spatial streams + * bits 6 - 7: reserved + * @i2r_ndp_params: parameters for I2R NDP ranging negotiation. + * bits 0 - 2: max LTF repetitions + * bits 3 - 5: max number of spatial streams (supported values are < 2) + * bits 6 - 7: reserved + * @r2i_max_total_ltf: R2I Max Total LTFs for NDP ranging negotiation. + * One of &enum ieee80211_range_params_max_total_ltf. + * @i2r_max_total_ltf: I2R Max Total LTFs for NDP ranging negotiation. + * One of &enum ieee80211_range_params_max_total_ltf. + * @bss_color: the BSS color of the responder. Only valid if + * &IWL_INITIATOR_AP_FLAGS_NON_TB or &IWL_INITIATOR_AP_FLAGS_TB is set. + * @band: 0 for 5.2 GHz, 1 for 2.4 GHz, 2 for 6GHz + * @min_time_between_msr: For non trigger based NDP ranging, the minimum time + * between measurements in units of milliseconds + */ +struct iwl_tof_range_req_ap_entry_v9 { + __le32 initiator_ap_flags; + u8 channel_num; + u8 format_bw; + u8 ctrl_ch_position; + u8 ftmr_max_retries; + u8 bssid[ETH_ALEN]; + __le16 burst_period; + u8 samples_per_burst; + u8 num_of_bursts; + u8 sta_id; + u8 cipher; + u8 hltk[HLTK_11AZ_LEN]; + u8 tk[TK_11AZ_LEN]; + __le16 calib[IWL_TOF_BW_NUM]; + u16 beacon_interval; + u8 rx_pn[IEEE80211_CCMP_PN_LEN]; + u8 tx_pn[IEEE80211_CCMP_PN_LEN]; + u8 r2i_ndp_params; + u8 i2r_ndp_params; + u8 r2i_max_total_ltf; + u8 i2r_max_total_ltf; + u8 bss_color; + u8 band; + __le16 min_time_between_msr; +} __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_9 */ + +/** * enum iwl_tof_response_mode * @IWL_MVM_TOF_RESPONSE_ASAP: report each AP measurement separately as soon as * possible (not supported for this release) @@ -1043,6 +1194,34 @@ struct iwl_tof_range_req_cmd_v12 { struct iwl_tof_range_req_ap_entry_v8 ap[IWL_MVM_TOF_MAX_APS]; } __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_12 */ +/** + * struct iwl_tof_range_req_cmd_v13 - start measurement cmd + * @initiator_flags: see flags @ iwl_tof_initiator_flags + * @request_id: A Token incremented per request. The same Token will be + * sent back in the range response + * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @range_req_bssid: ranging request BSSID + * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. + * Bits set to 1 shall be randomized by the UMAC + * @macaddr_template: MAC address template to use for non-randomized bits + * @req_timeout_ms: Requested timeout of the response in units of milliseconds. + * This is the session time for completing the measurement. + * @tsf_mac_id: report the measurement start time for each ap in terms of the + * TSF of this mac id. 0xff to disable TSF reporting. + * @ap: per-AP request data, see &struct iwl_tof_range_req_ap_entry_v9. + */ +struct iwl_tof_range_req_cmd_v13 { + __le32 initiator_flags; + u8 request_id; + u8 num_of_ap; + u8 range_req_bssid[ETH_ALEN]; + u8 macaddr_mask[ETH_ALEN]; + u8 macaddr_template[ETH_ALEN]; + __le32 req_timeout_ms; + __le32 tsf_mac_id; + struct iwl_tof_range_req_ap_entry_v9 ap[IWL_MVM_TOF_MAX_APS]; +} __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_13 */ + /* * enum iwl_tof_range_request_status - status of the sent request * @IWL_TOF_RANGE_REQUEST_STATUS_SUCCESSFUL - FW successfully received the diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 93084bbad534..7be7715b431d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_mac_h__ @@ -137,12 +137,14 @@ struct iwl_mac_data_ibss { * early termination detection. * @FLEXIBLE_TWT_SUPPORTED: AP supports flexible TWT schedule * @PROTECTED_TWT_SUPPORTED: AP supports protected TWT frames (with 11w) + * @BROADCAST_TWT_SUPPORTED: AP and STA support broadcast TWT */ enum iwl_mac_data_policy { TWT_SUPPORTED = BIT(0), MORE_DATA_ACK_SUPPORTED = BIT(1), FLEXIBLE_TWT_SUPPORTED = BIT(2), PROTECTED_TWT_SUPPORTED = BIT(3), + BROADCAST_TWT_SUPPORTED = BIT(4), }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h index f06214d418aa..5204aa94e72a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h @@ -3,6 +3,7 @@ * Copyright (C) 2012-2014 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2021 Intel Corporation */ #ifndef __iwl_fw_api_offload_h__ #define __iwl_fw_api_offload_h__ @@ -20,7 +21,7 @@ enum iwl_prot_offload_subcmd_ids { #define MAX_STORED_BEACON_SIZE 600 /** - * struct iwl_stored_beacon_notif - Stored beacon notification + * struct iwl_stored_beacon_notif_common - Stored beacon notif common fields * * @system_time: system time on air rise * @tsf: TSF on air rise @@ -29,9 +30,8 @@ enum iwl_prot_offload_subcmd_ids { * @channel: channel this beacon was received on * @rates: rate in ucode internal format * @byte_count: frame's byte count - * @data: beacon data, length in @byte_count */ -struct iwl_stored_beacon_notif { +struct iwl_stored_beacon_notif_common { __le32 system_time; __le64 tsf; __le32 beacon_timestamp; @@ -39,7 +39,32 @@ struct iwl_stored_beacon_notif { __le16 channel; __le32 rates; __le32 byte_count; +} __packed; + +/** + * struct iwl_stored_beacon_notif - Stored beacon notification + * + * @common: fields common for all versions + * @data: beacon data, length in @byte_count + */ +struct iwl_stored_beacon_notif_v2 { + struct iwl_stored_beacon_notif_common common; u8 data[MAX_STORED_BEACON_SIZE]; } __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_2 */ +/** + * struct iwl_stored_beacon_notif_v3 - Stored beacon notification + * + * @common: fields common for all versions + * @sta_id: station for which the beacon was received + * @reserved: reserved for alignment + * @data: beacon data, length in @byte_count + */ +struct iwl_stored_beacon_notif_v3 { + struct iwl_stored_beacon_notif_common common; + u8 sta_id; + u8 reserved[3]; + u8 data[MAX_STORED_BEACON_SIZE]; +} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_3 */ + #endif /* __iwl_fw_api_offload_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index b2605aefc290..8b200379f7c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -874,7 +874,7 @@ struct iwl_scan_probe_params_v3 { u8 reserved; struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; __le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE]; - u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE]; + u8 bssid_array[SCAN_BSSID_MAX_SIZE][ETH_ALEN]; } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_3 */ /** @@ -894,7 +894,7 @@ struct iwl_scan_probe_params_v4 { __le16 reserved; struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; __le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE]; - u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE]; + u8 bssid_array[SCAN_BSSID_MAX_SIZE][ETH_ALEN]; } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */ #define SCAN_MAX_NUM_CHANS_V3 67 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h index 12b2f2c48387..f1a3e14880e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -384,13 +384,17 @@ struct iwl_mvm_add_sta_key_cmd_v1 { * @rx_mic_key: TKIP RX unicast or multicast key * @tx_mic_key: TKIP TX key * @transmit_seq_cnt: TSC, transmit packet number + * + * Note: This is used for both v2 and v3, the difference being + * in the way the common.rx_secur_seq_cnt is used, in v2 that's + * the strange hole format, in v3 it's just a u64. */ struct iwl_mvm_add_sta_key_cmd { struct iwl_mvm_add_sta_key_common common; __le64 rx_mic_key; __le64 tx_mic_key; __le64 transmit_seq_cnt; -} __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_2 */ +} __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_2, ADD_MODIFY_STA_KEY_API_S_VER_3 */ /** * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index df7c55e06f54..6dcafd0a3d4b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1517,6 +1517,37 @@ iwl_dump_ini_special_mem_iter(struct iwl_fw_runtime *fwrt, return sizeof(*range) + le32_to_cpu(range->range_data_size); } +static int +iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + __le32 *val = range->data; + u32 prph_data; + int i; + + if (!iwl_trans_grab_nic_access(fwrt->trans)) + return -EBUSY; + + range->range_data_size = reg->dev_addr.size; + iwl_write_prph_no_grab(fwrt->trans, DBGI_SRAM_TARGET_ACCESS_CFG, + DBGI_SRAM_TARGET_ACCESS_CFG_RESET_ADDRESS_MSK); + for (i = 0; i < (le32_to_cpu(reg->dev_addr.size) / 4); i++) { + prph_data = iwl_read_prph(fwrt->trans, (i % 2) ? + DBGI_SRAM_TARGET_ACCESS_RDATA_MSB : + DBGI_SRAM_TARGET_ACCESS_RDATA_LSB); + if (prph_data == 0x5a5a5a5a) { + iwl_trans_release_nic_access(fwrt->trans); + return -EBUSY; + } + *val++ = cpu_to_le32(prph_data); + } + iwl_trans_release_nic_access(fwrt->trans); + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + static int iwl_dump_ini_fw_pkt_iter(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) @@ -1547,7 +1578,7 @@ iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER); - return dump->ranges; + return dump->data; } /** @@ -1611,7 +1642,7 @@ iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, data->header.version = cpu_to_le32(IWL_INI_DUMP_VER); - return data->ranges; + return data->data; } static void * @@ -1647,7 +1678,7 @@ iwl_dump_ini_err_table_fill_header(struct iwl_fw_runtime *fwrt, dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER); dump->version = reg->err_table.version; - return dump->ranges; + return dump->data; } static void * @@ -1662,7 +1693,7 @@ iwl_dump_ini_special_mem_fill_header(struct iwl_fw_runtime *fwrt, dump->type = reg->special_mem.type; dump->version = reg->special_mem.version; - return dump->ranges; + return dump->data; } static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt, @@ -2189,6 +2220,12 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .fill_mem_hdr = iwl_dump_ini_special_mem_fill_header, .fill_range = iwl_dump_ini_special_mem_iter, }, + [IWL_FW_INI_REGION_DBGI_SRAM] = { + .get_num_of_ranges = iwl_dump_ini_mem_ranges, + .get_size = iwl_dump_ini_mem_get_size, + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .fill_range = iwl_dump_ini_dbgi_sram_iter, + }, }; static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, @@ -2321,7 +2358,7 @@ static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, return; if (dump_data->monitor_only) - dump_mask &= IWL_FW_ERROR_DUMP_FW_MONITOR; + dump_mask &= BIT(IWL_FW_ERROR_DUMP_FW_MONITOR); fw_error_dump.trans_ptr = iwl_trans_dump_data(fwrt->trans, dump_mask); file_len = le32_to_cpu(dump_file->file_len); @@ -2530,51 +2567,6 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect); -int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, - struct iwl_fwrt_dump_data *dump_data) -{ - struct iwl_fw_ini_trigger_tlv *trig = dump_data->trig; - enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point); - u32 occur, delay; - unsigned long idx; - - if (!iwl_fw_ini_trigger_on(fwrt, trig)) { - IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n", - tp_id); - return -EINVAL; - } - - delay = le32_to_cpu(trig->dump_delay); - occur = le32_to_cpu(trig->occurrences); - if (!occur) - return 0; - - trig->occurrences = cpu_to_le32(--occur); - - /* Check there is an available worker. - * ffz return value is undefined if no zero exists, - * so check against ~0UL first. - */ - if (fwrt->dump.active_wks == ~0UL) - return -EBUSY; - - idx = ffz(fwrt->dump.active_wks); - - if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM || - test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks)) - return -EBUSY; - - fwrt->dump.wks[idx].dump_data = *dump_data; - - IWL_WARN(fwrt, - "WRT: Collecting data: ini trigger %d fired (delay=%dms).\n", - tp_id, (u32)(delay / USEC_PER_MSEC)); - - schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay)); - - return 0; -} - int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger, const char *fmt, ...) @@ -2703,6 +2695,58 @@ out: clear_bit(wk_idx, &fwrt->dump.active_wks); } +int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data, + bool sync) +{ + struct iwl_fw_ini_trigger_tlv *trig = dump_data->trig; + enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point); + u32 occur, delay; + unsigned long idx; + + if (!iwl_fw_ini_trigger_on(fwrt, trig)) { + IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n", + tp_id); + return -EINVAL; + } + + delay = le32_to_cpu(trig->dump_delay); + occur = le32_to_cpu(trig->occurrences); + if (!occur) + return 0; + + trig->occurrences = cpu_to_le32(--occur); + + /* Check there is an available worker. + * ffz return value is undefined if no zero exists, + * so check against ~0UL first. + */ + if (fwrt->dump.active_wks == ~0UL) + return -EBUSY; + + idx = ffz(fwrt->dump.active_wks); + + if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM || + test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks)) + return -EBUSY; + + fwrt->dump.wks[idx].dump_data = *dump_data; + + if (sync) + delay = 0; + + IWL_WARN(fwrt, + "WRT: Collecting data: ini trigger %d fired (delay=%dms).\n", + tp_id, (u32)(delay / USEC_PER_MSEC)); + + schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay)); + + if (sync) + iwl_fw_dbg_collect_sync(fwrt, idx); + + return 0; +} + void iwl_fw_error_dump_wk(struct work_struct *work) { struct iwl_fwrt_wk_data *wks = diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index c0e84ef84f5d..8c3c890066b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -46,7 +46,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig_type); int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, - struct iwl_fwrt_dump_data *dump_data); + struct iwl_fwrt_dump_data *dump_data, + bool sync); int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig, const char *str, size_t len, struct iwl_fw_dbg_trigger_tlv *trigger); @@ -284,7 +285,7 @@ static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans, trans->dbg.umac_error_event_table = umac_error_event_table; } -static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt) +static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt, bool sync) { enum iwl_fw_ini_time_point tp_id; @@ -300,7 +301,7 @@ static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt) tp_id = IWL_FW_INI_TIME_POINT_FW_ASSERT; } - iwl_dbg_tlv_time_point(fwrt, tp_id, NULL); + _iwl_dbg_tlv_time_point(fwrt, tp_id, NULL, sync); } void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 9fffac903b93..521ca2bb0e92 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2014, 2018-2020 Intel Corporation + * Copyright (C) 2014, 2018-2021 Intel Corporation * Copyright (C) 2014-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -305,11 +305,12 @@ struct iwl_fw_ini_error_dump_header { /** * struct iwl_fw_ini_error_dump - ini region dump * @header: the header of this region - * @ranges: the memory ranges of this region + * @data: data of memory ranges in this region, + * see &struct iwl_fw_ini_error_dump_range */ struct iwl_fw_ini_error_dump { struct iwl_fw_ini_error_dump_header header; - struct iwl_fw_ini_error_dump_range ranges[]; + u8 data[]; } __packed; /* This bit is used to differentiate between lmac and umac rxf */ @@ -399,12 +400,13 @@ struct iwl_fw_ini_dump_info { * struct iwl_fw_ini_err_table_dump - ini error table dump * @header: header of the region * @version: error table version - * @ranges: the memory ranges of this this region + * @data: data of memory ranges in this region, + * see &struct iwl_fw_ini_error_dump_range */ struct iwl_fw_ini_err_table_dump { struct iwl_fw_ini_error_dump_header header; __le32 version; - struct iwl_fw_ini_error_dump_range ranges[]; + u8 data[]; } __packed; /** @@ -427,14 +429,15 @@ struct iwl_fw_error_dump_rb { * @write_ptr: write pointer position in the buffer * @cycle_cnt: cycles count * @cur_frag: current fragment in use - * @ranges: the memory ranges of this this region + * @data: data of memory ranges in this region, + * see &struct iwl_fw_ini_error_dump_range */ struct iwl_fw_ini_monitor_dump { struct iwl_fw_ini_error_dump_header header; __le32 write_ptr; __le32 cycle_cnt; __le32 cur_frag; - struct iwl_fw_ini_error_dump_range ranges[]; + u8 data[]; } __packed; /** @@ -442,13 +445,14 @@ struct iwl_fw_ini_monitor_dump { * @header: header of the region * @type: type of special memory * @version: struct special memory version - * @ranges: the memory ranges of this this region + * @data: data of memory ranges in this region, + * see &struct iwl_fw_ini_error_dump_range */ struct iwl_fw_ini_special_device_memory { struct iwl_fw_ini_error_dump_header header; __le16 type; __le16 version; - struct iwl_fw_ini_error_dump_range ranges[]; + u8 data[]; } __packed; /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 9a8c7b7a0816..6c8e9f3a6af2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -414,6 +414,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_PROTECTED_TWT = (__force iwl_ucode_tlv_capa_t)56, IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE = (__force iwl_ucode_tlv_capa_t)57, IWL_UCODE_TLV_CAPA_PASSIVE_6GHZ_SCAN = (__force iwl_ucode_tlv_capa_t)58, + IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN = (__force iwl_ucode_tlv_capa_t)59, IWL_UCODE_TLV_CAPA_BROADCAST_TWT = (__force iwl_ucode_tlv_capa_t)60, /* set 2 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 2403490cbc26..314ed90c23dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -24,7 +24,7 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data; IWL_DEBUG_FW(trans, - "PNVM complete notification received with status %d\n", + "PNVM complete notification received with status 0x%0x\n", le32_to_cpu(pnvm_ntf->status)); return true; @@ -37,6 +37,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, u32 sha1 = 0; u16 mac_type = 0, rf_id = 0; u8 *pnvm_data = NULL, *tmp; + bool hw_match = false; u32 size = 0; int ret; @@ -83,6 +84,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, break; } + if (hw_match) + break; + mac_type = le16_to_cpup((__le16 *)data); rf_id = le16_to_cpup((__le16 *)(data + sizeof(__le16))); @@ -90,15 +94,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, "Got IWL_UCODE_TLV_HW_TYPE mac_type 0x%0x rf_id 0x%0x\n", mac_type, rf_id); - if (mac_type != CSR_HW_REV_TYPE(trans->hw_rev) || - rf_id != CSR_HW_RFID_TYPE(trans->hw_rf_id)) { - IWL_DEBUG_FW(trans, - "HW mismatch, skipping PNVM section, mac_type 0x%0x, rf_id 0x%0x.\n", - CSR_HW_REV_TYPE(trans->hw_rev), trans->hw_rf_id); - ret = -ENOENT; - goto out; - } - + if (mac_type == CSR_HW_REV_TYPE(trans->hw_rev) && + rf_id == CSR_HW_RFID_TYPE(trans->hw_rf_id)) + hw_match = true; break; case IWL_UCODE_TLV_SEC_RT: { struct iwl_pnvm_section *section = (void *)data; @@ -149,6 +147,15 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, } done: + if (!hw_match) { + IWL_DEBUG_FW(trans, + "HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n", + CSR_HW_REV_TYPE(trans->hw_rev), + CSR_HW_RFID_TYPE(trans->hw_rf_id)); + ret = -ENOENT; + goto out; + } + if (!size) { IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); ret = -ENOENT; @@ -223,19 +230,10 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) { const struct firmware *pnvm; - char pnvm_name[64]; + char pnvm_name[MAX_PNVM_NAME]; int ret; - /* - * The prefix unfortunately includes a hyphen at the end, so - * don't add the dot here... - */ - snprintf(pnvm_name, sizeof(pnvm_name), "%spnvm", - trans->cfg->fw_name_pre); - - /* ...but replace the hyphen with the dot here. */ - if (strlen(trans->cfg->fw_name_pre) < sizeof(pnvm_name)) - pnvm_name[strlen(trans->cfg->fw_name_pre) - 1] = '.'; + iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name)); ret = firmware_request_nowarn(&pnvm, pnvm_name, trans->dev); if (ret) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index 61d3d4e0b7d9..203c367dd4de 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -12,7 +12,27 @@ #define MVM_UCODE_PNVM_TIMEOUT (HZ / 4) +#define MAX_PNVM_NAME 64 + int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait); +static inline +void iwl_pnvm_get_fs_name(struct iwl_trans *trans, + u8 *pnvm_name, size_t max_len) +{ + int pre_len; + + /* + * The prefix unfortunately includes a hyphen at the end, so + * don't add the dot here... + */ + snprintf(pnvm_name, max_len, "%spnvm", trans->cfg->fw_name_pre); + + /* ...but replace the hyphen with the dot here. */ + pre_len = strlen(trans->cfg->fw_name_pre); + if (pre_len < max_len && pre_len > 0) + pnvm_name[pre_len - 1] = '.'; +} + #endif /* __IWL_PNVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index bf6ee56d4d96..7eb534df5331 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -33,6 +33,7 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_9000, IWL_DEVICE_FAMILY_22000, IWL_DEVICE_FAMILY_AX210, + IWL_DEVICE_FAMILY_BZ, }; /* @@ -321,7 +322,7 @@ struct iwl_fw_mon_regs { * @host_interrupt_operation_mode: device needs host interrupt operation * mode set * @nvm_hw_section_num: the ID of the HW NVM section - * @mac_addr_from_csr: read HW address from CSR registers + * @mac_addr_from_csr: read HW address from CSR registers at this offset * @features: hw features, any combination of feature_passlist * @pwr_tx_backoffs: translation table between power limits and backoffs * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response @@ -343,6 +344,8 @@ struct iwl_fw_mon_regs { * supports 256 BA aggregation * @num_rbds: number of receive buffer descriptors to use * (only used for multi-queue capable devices) + * @mac_addr_csr_base: CSR base register for MAC address access, if not set + * assume 0x380 * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -378,7 +381,7 @@ struct iwl_cfg { internal_wimax_coex:1, host_interrupt_operation_mode:1, high_temp:1, - mac_addr_from_csr:1, + mac_addr_from_csr:10, lp_xtal_workaround:1, disable_dummy_notification:1, apmg_not_supported:1, @@ -512,6 +515,7 @@ extern const char iwl_ax211_name[]; extern const char iwl_ax221_name[]; extern const char iwl_ax231_name[]; extern const char iwl_ax411_name[]; +extern const char iwl_bz_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; extern const struct iwl_cfg iwl5100_agn_cfg; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 47e5a17c0f48..cf796403c45c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -104,6 +104,10 @@ /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +/* Doorbell NMI (since Bz) */ +#define CSR_DOORBELL_VECTOR (CSR_BASE + 0x130) +#define CSR_DOORBELL_VECTOR_NMI BIT(1) + /* host chicken bits */ #define CSR_HOST_CHICKEN (CSR_BASE + 0x204) #define CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME BIT(19) @@ -266,6 +270,14 @@ #define CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN (0x04000000) #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) +/* From Bz we use these instead during init/reset flow */ +#define CSR_GP_CNTRL_REG_FLAG_MAC_INIT BIT(6) +#define CSR_GP_CNTRL_REG_FLAG_ROM_START BIT(7) +#define CSR_GP_CNTRL_REG_FLAG_MAC_STATUS BIT(20) +#define CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ BIT(21) +#define CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS BIT(28) +#define CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ BIT(29) +#define CSR_GP_CNTRL_REG_FLAG_SW_RESET BIT(31) /* HW REV */ #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) @@ -604,10 +616,10 @@ enum msix_hw_int_causes { * HW address related registers * *****************************************************************************/ -#define CSR_ADDR_BASE (0x380) -#define CSR_MAC_ADDR0_OTP (CSR_ADDR_BASE) -#define CSR_MAC_ADDR1_OTP (CSR_ADDR_BASE + 4) -#define CSR_MAC_ADDR0_STRAP (CSR_ADDR_BASE + 8) -#define CSR_MAC_ADDR1_STRAP (CSR_ADDR_BASE + 0xC) +#define CSR_ADDR_BASE(trans) ((trans)->cfg->mac_addr_from_csr) +#define CSR_MAC_ADDR0_OTP(trans) (CSR_ADDR_BASE(trans) + 0x00) +#define CSR_MAC_ADDR1_OTP(trans) (CSR_ADDR_BASE(trans) + 0x04) +#define CSR_MAC_ADDR0_STRAP(trans) (CSR_ADDR_BASE(trans) + 0x08) +#define CSR_MAC_ADDR1_STRAP(trans) (CSR_ADDR_BASE(trans) + 0x0c) #endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 0ddd255a8cc1..125479b5c0d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -131,8 +131,7 @@ static int iwl_dbg_tlv_alloc_buf_alloc(struct iwl_trans *trans, goto err; if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH && - alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1 && - alloc_id != IWL_FW_INI_ALLOCATION_ID_INTERNAL) + alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1) goto err; trans->dbg.fw_mon_cfg[alloc_id] = *alloc; @@ -435,13 +434,16 @@ static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data, void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) { const struct firmware *fw; + const char *yoyo_bin = "iwl-debug-yoyo.bin"; int res; if (!iwlwifi_mod_params.enable_ini || trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_9000) return; - res = firmware_request_nowarn(&fw, "iwl-debug-yoyo.bin", dev); + res = firmware_request_nowarn(&fw, yoyo_bin, dev); + IWL_DEBUG_FW(trans, "%s %s\n", res ? "didn't load" : "loaded", yoyo_bin); + if (res) return; @@ -621,6 +623,7 @@ static int iwl_dbg_tlv_apply_buffer(struct iwl_fw_runtime *fwrt, .id = WIDE_ID(DEBUG_GROUP, BUFFER_ALLOCATION), .data[0] = &data, .len[0] = sizeof(data), + .flags = CMD_SEND_IN_RFKILL, }; int ret, j; @@ -683,7 +686,7 @@ static void iwl_dbg_tlv_periodic_trig_handler(struct timer_list *t) }; int ret; - ret = iwl_fw_dbg_ini_collect(timer_node->fwrt, &dump_data); + ret = iwl_fw_dbg_ini_collect(timer_node->fwrt, &dump_data, false); if (!ret || ret == -EBUSY) { u32 occur = le32_to_cpu(dump_data.trig->occurrences); u32 collect_interval = le32_to_cpu(dump_data.trig->data[0]); @@ -927,7 +930,7 @@ static bool iwl_dbg_tlv_check_fw_pkt(struct iwl_fw_runtime *fwrt, } static int -iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, +iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, struct list_head *active_trig_list, union iwl_dbg_tlv_tp_data *tp_data, bool (*data_check)(struct iwl_fw_runtime *fwrt, @@ -946,7 +949,7 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, int ret, i; if (!num_data) { - ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data); + ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data, sync); if (ret) return ret; } @@ -955,7 +958,7 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, if (!data_check || data_check(fwrt, &dump_data, tp_data, le32_to_cpu(dump_data.trig->data[i]))) { - ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data); + ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data, sync); if (ret) return ret; @@ -1043,9 +1046,10 @@ static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) } } -void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_time_point tp_id, - union iwl_dbg_tlv_tp_data *tp_data) +void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data, + bool sync) { struct list_head *hcmd_list, *trig_list; @@ -1060,12 +1064,12 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, switch (tp_id) { case IWL_FW_INI_TIME_POINT_EARLY: iwl_dbg_tlv_init_cfg(fwrt); - iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); break; case IWL_FW_INI_TIME_POINT_AFTER_ALIVE: iwl_dbg_tlv_apply_buffers(fwrt); iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); - iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); break; case IWL_FW_INI_TIME_POINT_PERIODIC: iwl_dbg_tlv_set_periodic_trigs(fwrt); @@ -1075,13 +1079,13 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, case IWL_FW_INI_TIME_POINT_MISSED_BEACONS: case IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFICATION: iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); - iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, iwl_dbg_tlv_check_fw_pkt); break; default: iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); - iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); break; } } -IWL_EXPORT_SYMBOL(iwl_dbg_tlv_time_point); +IWL_EXPORT_SYMBOL(_iwl_dbg_tlv_time_point); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index 92c720527946..c12b1fd3f479 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #ifndef __iwl_dbg_tlv_h__ #define __iwl_dbg_tlv_h__ @@ -48,9 +48,25 @@ void iwl_dbg_tlv_free(struct iwl_trans *trans); void iwl_dbg_tlv_alloc(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv, bool ext); void iwl_dbg_tlv_init(struct iwl_trans *trans); -void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_time_point tp_id, - union iwl_dbg_tlv_tp_data *tp_data); +void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data, + bool sync); + +static inline void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data) +{ + _iwl_dbg_tlv_time_point(fwrt, tp_id, tp_data, false); +} + +static inline void iwl_dbg_tlv_time_point_sync(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data) +{ + _iwl_dbg_tlv_time_point(fwrt, tp_id, tp_data, true); +} + void iwl_dbg_tlv_del_timers(struct iwl_trans *trans); #endif /* __iwl_dbg_tlv_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 977dce686bdb..77124b8b235e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -78,7 +78,7 @@ enum { }; /* Protects the table contents, i.e. the ops pointer & drv list */ -static struct mutex iwlwifi_opmode_table_mtx; +static DEFINE_MUTEX(iwlwifi_opmode_table_mtx); static struct iwlwifi_opmode_table { const char *name; /* name: iwldvm, iwlmvm, etc */ const struct iwl_op_mode_ops *ops; /* pointer to op_mode ops */ @@ -1754,8 +1754,6 @@ static int __init iwl_drv_init(void) { int i, err; - mutex_init(&iwlwifi_opmode_table_mtx); - for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 33d42e08d5b8..2517c4ae07ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2003-2014, 2018-2020 Intel Corporation + * Copyright (C) 2003-2014, 2018-2021 Intel Corporation * Copyright (C) 2015-2016 Intel Deutschland GmbH */ #include <linux/delay.h> @@ -213,9 +213,12 @@ void iwl_force_nmi(struct iwl_trans *trans) else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER); - else + else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ) iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, UREG_DOORBELL_TO_ISR6_NMI_BIT); + else + iwl_write32(trans, CSR_DOORBELL_VECTOR, + CSR_DOORBELL_VECTOR_NMI); } IWL_EXPORT_SYMBOL(iwl_force_nmi); @@ -398,6 +401,7 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf) int iwl_finish_nic_init(struct iwl_trans *trans, const struct iwl_cfg_trans_params *cfg_trans) { + u32 poll_ready; int err; if (cfg_trans->bisr_workaround) { @@ -409,7 +413,16 @@ int iwl_finish_nic_init(struct iwl_trans *trans, * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ - iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + if (cfg_trans->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; + } else { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY; + } if (cfg_trans->device_family == IWL_DEVICE_FAMILY_8000) udelay(2); @@ -419,10 +432,7 @@ int iwl_finish_nic_init(struct iwl_trans *trans, * device-internal resources is supported, e.g. iwl_write_prph() * and accesses to uCode SRAM. */ - err = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - 25000); + err = iwl_poll_bit(trans, CSR_GP_CNTRL, poll_ready, poll_ready, 25000); if (err < 0) IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); @@ -468,5 +478,5 @@ void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, if (interrupts_enabled) iwl_trans_interrupts(trans, true); - iwl_trans_fw_error(trans); + iwl_trans_fw_error(trans, false); } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 850648ebd61c..475f951d4b1e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -549,7 +549,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_OMI_CONTROL, + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, @@ -568,7 +569,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, .phy_cap_info[2] = - IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ, .phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | @@ -595,6 +597,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, + .phy_cap_info[10] = + IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF, }, /* * Set default Tx/Rx HE MCS NSS Support field. @@ -634,6 +638,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, .phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, .phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | @@ -742,6 +747,8 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; if ((tx_chains & rx_chains) == ANT_AB) { + iftype_data->he_cap.he_cap_elem.phy_cap_info[2] |= + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ; iftype_data->he_cap.he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2; @@ -958,8 +965,10 @@ static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, struct iwl_nvm_data *data) { - __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP)); - __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP)); + __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, + CSR_MAC_ADDR0_STRAP(trans))); + __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, + CSR_MAC_ADDR1_STRAP(trans))); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); /* @@ -969,8 +978,8 @@ static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, if (is_valid_ether_addr(data->hw_addr)) return; - mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP)); - mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP)); + mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP(trans))); + mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP(trans))); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); } @@ -1373,6 +1382,25 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, reg_query_regdb_wmm(regd->alpha2, center_freq, rule); } + /* + * Certain firmware versions might report no valid channels + * if booted in RF-kill, i.e. not all calibrations etc. are + * running. We'll get out of this situation later when the + * rfkill is removed and we update the regdomain again, but + * since cfg80211 doesn't accept an empty regdomain, add a + * dummy (unusable) rule here in this case so we can init. + */ + if (!valid_rules) { + valid_rules = 1; + rule = ®d->reg_rules[valid_rules - 1]; + rule->freq_range.start_freq_khz = MHZ_TO_KHZ(2412); + rule->freq_range.end_freq_khz = MHZ_TO_KHZ(2413); + rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(1); + rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); + rule->power_rule.max_eirp = + DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); + } + regd->n_reg_rules = valid_rules; /* diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index cf9c64090014..af5f9b210f22 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -78,7 +78,7 @@ struct iwl_cfg; * there are Tx packets pending in the transport layer. * Must be atomic * @nic_error: error notification. Must be atomic and must be called with BH - * disabled. + * disabled, unless the sync parameter is true. * @cmd_queue_full: Called when the command queue gets full. Must be atomic and * called with BH disabled. * @nic_config: configure NIC, called before firmware is started. @@ -102,7 +102,7 @@ struct iwl_op_mode_ops { void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb); - void (*nic_error)(struct iwl_op_mode *op_mode); + void (*nic_error)(struct iwl_op_mode *op_mode, bool sync); void (*cmd_queue_full)(struct iwl_op_mode *op_mode); void (*nic_config)(struct iwl_op_mode *op_mode); void (*wimax_active)(struct iwl_op_mode *op_mode); @@ -181,9 +181,9 @@ static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode, op_mode->ops->free_skb(op_mode, skb); } -static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode) +static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode, bool sync) { - op_mode->ops->nic_error(op_mode); + op_mode->ops->nic_error(op_mode, sync); } static inline void iwl_op_mode_cmd_queue_full(struct iwl_op_mode *op_mode) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 9a9e714bf9af..d0a7d58336a9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -348,6 +348,13 @@ #define RFIC_REG_RD 0xAD0470 #define WFPM_CTRL_REG 0xA03030 #define WFPM_GP2 0xA030B4 + +/* DBGI SRAM Register details */ +#define DBGI_SRAM_TARGET_ACCESS_CFG 0x00A2E14C +#define DBGI_SRAM_TARGET_ACCESS_CFG_RESET_ADDRESS_MSK 0x10000 +#define DBGI_SRAM_TARGET_ACCESS_RDATA_LSB 0x00A2E154 +#define DBGI_SRAM_TARGET_ACCESS_RDATA_MSB 0x00A2E158 + enum { ENABLE_WFPM = BIT(31), WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0199d7a5a648..8f0ff540f439 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -887,7 +887,7 @@ struct iwl_trans_txqs { bool bc_table_dword; u8 page_offs; u8 dev_cmd_offs; - struct __percpu iwl_tso_hdr_page * tso_hdr_page; + struct iwl_tso_hdr_page __percpu *tso_hdr_page; struct { u8 fifo; @@ -1385,14 +1385,14 @@ iwl_trans_release_nic_access(struct iwl_trans *trans) __release(nic_access); } -static inline void iwl_trans_fw_error(struct iwl_trans *trans) +static inline void iwl_trans_fw_error(struct iwl_trans *trans, bool sync) { if (WARN_ON_ONCE(!trans->op_mode)) return; /* prevent double restarts due to the same erroneous FW */ if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status)) { - iwl_op_mode_nic_error(trans->op_mode); + iwl_op_mode_nic_error(trans->op_mode, sync); trans->state = IWL_TRANS_NO_FW; } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 1343f25f1090..9d0d01f27d92 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2013-2014, 2018-2020 Intel Corporation + * Copyright (C) 2013-2014, 2018-2021 Intel Corporation * Copyright (C) 2015 Intel Deutschland GmbH */ #ifndef __MVM_CONSTANTS_H @@ -93,6 +93,7 @@ #define IWL_MVM_ENABLE_EBS 1 #define IWL_MVM_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE #define IWL_MVM_FTM_INITIATOR_DYNACK true +#define IWL_MVM_FTM_LMR_FEEDBACK_TERMINATE false #define IWL_MVM_FTM_R2I_MAX_REP 7 #define IWL_MVM_FTM_I2R_MAX_REP 7 #define IWL_MVM_FTM_R2I_MAX_STS 1 @@ -102,6 +103,8 @@ #define IWL_MVM_FTM_INITIATOR_SECURE_LTF false #define IWL_MVM_FTM_RESP_NDP_SUPPORT true #define IWL_MVM_FTM_RESP_LMR_FEEDBACK_SUPPORT true +#define IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR 5 +#define IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR 1000 #define IWL_MVM_D3_DEBUG false #define IWL_MVM_USE_TWT true #define IWL_MVM_AMPDU_CONSEC_DROPS_DELBA 10 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 6a259d867d90..0e97d5e6c644 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -101,11 +101,8 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key, return ret; } -struct wowlan_key_data { - struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; - struct iwl_wowlan_tkip_params_cmd *tkip; - struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; - bool error, use_rsc_tsc, use_tkip, configure_keys; +struct wowlan_key_reprogram_data { + bool error; int wep_key_idx; }; @@ -117,15 +114,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct wowlan_key_data *data = _data; - struct aes_sc *aes_sc, *aes_tx_sc = NULL; - struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; - struct iwl_p1k_cache *rx_p1ks; - u8 *rx_mic_key; - struct ieee80211_key_seq seq; - u32 cur_rx_iv32 = 0; - u16 p1k[IWL_P1K_SIZE]; - int ret, i; + struct wowlan_key_reprogram_data *data = _data; + int ret; switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: @@ -162,18 +152,14 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, wkc.wep_key.key_offset = data->wep_key_idx; } - if (data->configure_keys) { - mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, - sizeof(wkc), &wkc); - data->error = ret != 0; - - mvm->ptk_ivlen = key->iv_len; - mvm->ptk_icvlen = key->icv_len; - mvm->gtk_ivlen = key->iv_len; - mvm->gtk_icvlen = key->icv_len; - mutex_unlock(&mvm->mutex); - } + mutex_lock(&mvm->mutex); + ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, sizeof(wkc), &wkc); + data->error = ret != 0; + + mvm->ptk_ivlen = key->iv_len; + mvm->ptk_icvlen = key->icv_len; + mvm->gtk_ivlen = key->iv_len; + mvm->gtk_icvlen = key->icv_len; /* don't upload key again */ return; @@ -183,10 +169,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, return; case WLAN_CIPHER_SUITE_BIP_GMAC_256: case WLAN_CIPHER_SUITE_BIP_GMAC_128: - data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_GCMP); return; case WLAN_CIPHER_SUITE_AES_CMAC: - data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_CCM); /* * Ignore CMAC keys -- the WoWLAN firmware doesn't support them * but we also shouldn't abort suspend due to that. It does have @@ -196,6 +180,58 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, */ return; case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + break; + } + + mutex_lock(&mvm->mutex); + /* + * The D3 firmware hardcodes the key offset 0 as the key it + * uses to transmit packets to the AP, i.e. the PTK. + */ + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + mvm->ptk_ivlen = key->iv_len; + mvm->ptk_icvlen = key->icv_len; + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0); + } else { + /* + * firmware only supports TSC/RSC for a single key, + * so if there are multiple keep overwriting them + * with new ones -- this relies on mac80211 doing + * list_add_tail(). + */ + mvm->gtk_ivlen = key->iv_len; + mvm->gtk_icvlen = key->icv_len; + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1); + } + mutex_unlock(&mvm->mutex); + data->error = ret != 0; +} + +struct wowlan_key_rsc_tsc_data { + struct iwl_wowlan_rsc_tsc_params_cmd_v4 *rsc_tsc; + bool have_rsc_tsc; +}; + +static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct wowlan_key_rsc_tsc_data *data = _data; + struct aes_sc *aes_sc; + struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; + struct ieee80211_key_seq seq; + int i; + + switch (key->cipher) { + default: + break; + case WLAN_CIPHER_SUITE_TKIP: if (sta) { u64 pn64; @@ -204,28 +240,12 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, tkip_tx_sc = &data->rsc_tsc->params.all_tsc_rsc.tkip.tsc; - rx_p1ks = data->tkip->rx_uni; - pn64 = atomic64_read(&key->tx_pn); tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64)); tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64)); - - ieee80211_get_tkip_p1k_iv(key, TKIP_PN_TO_IV32(pn64), - p1k); - iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k); - - memcpy(data->tkip->mic_keys.tx, - &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], - IWL_MIC_KEY_SIZE); - - rx_mic_key = data->tkip->mic_keys.rx_unicast; } else { tkip_sc = data->rsc_tsc->params.all_tsc_rsc.tkip.multicast_rsc; - rx_p1ks = data->tkip->rx_multi; - rx_mic_key = data->tkip->mic_keys.rx_mcast; - data->kek_kck_cmd->gtk_cipher = - cpu_to_le32(STA_KEY_FLG_TKIP); } /* @@ -237,29 +257,15 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ieee80211_get_key_rx_seq(key, i, &seq); tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16); tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32); - /* wrapping isn't allowed, AP must rekey */ - if (seq.tkip.iv32 > cur_rx_iv32) - cur_rx_iv32 = seq.tkip.iv32; } - ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, - cur_rx_iv32, p1k); - iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k); - ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, - cur_rx_iv32 + 1, p1k); - iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k); - - memcpy(rx_mic_key, - &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], - IWL_MIC_KEY_SIZE); - - data->use_tkip = true; - data->use_rsc_tsc = true; + data->have_rsc_tsc = true; break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: if (sta) { + struct aes_sc *aes_tx_sc; u64 pn64; aes_sc = @@ -272,10 +278,6 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, } else { aes_sc = data->rsc_tsc->params.all_tsc_rsc.aes.multicast_rsc; - data->kek_kck_cmd->gtk_cipher = - key->cipher == WLAN_CIPHER_SUITE_CCMP ? - cpu_to_le32(STA_KEY_FLG_CCM) : - cpu_to_le32(STA_KEY_FLG_GCMP); } /* @@ -320,35 +322,301 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ((u64)pn[0] << 40)); } } - data->use_rsc_tsc = true; + data->have_rsc_tsc = true; break; } +} - IWL_DEBUG_WOWLAN(mvm, "GTK cipher %d\n", data->kek_kck_cmd->gtk_cipher); +struct wowlan_key_rsc_v5_data { + struct iwl_wowlan_rsc_tsc_params_cmd *rsc; + bool have_rsc; + int gtks; + int gtk_ids[4]; +}; - if (data->configure_keys) { - mutex_lock(&mvm->mutex); +static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct wowlan_key_rsc_v5_data *data = _data; + struct ieee80211_key_seq seq; + __le64 *rsc; + int i; + + /* only for ciphers that can be PTK/GTK */ + switch (key->cipher) { + default: + return; + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + break; + } + + if (sta) { + rsc = data->rsc->ucast_rsc; + } else { + if (WARN_ON(data->gtks > ARRAY_SIZE(data->gtk_ids))) + return; + data->gtk_ids[data->gtks] = key->keyidx; + rsc = data->rsc->mcast_rsc[data->gtks % 2]; + if (WARN_ON(key->keyidx > + ARRAY_SIZE(data->rsc->mcast_key_id_map))) + return; + data->rsc->mcast_key_id_map[key->keyidx] = data->gtks % 2; + if (data->gtks >= 2) { + int prev = data->gtks - 2; + int prev_idx = data->gtk_ids[prev]; + + data->rsc->mcast_key_id_map[prev_idx] = + IWL_MCAST_KEY_MAP_INVALID; + } + data->gtks++; + } + + switch (key->cipher) { + default: + WARN_ON(1); + break; + case WLAN_CIPHER_SUITE_TKIP: + + /* + * For non-QoS this relies on the fact that both the uCode and + * mac80211 use TID 0 (as they need to to avoid replay attacks) + * for checking the IV in the frames. + */ + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + ieee80211_get_key_rx_seq(key, i, &seq); + + rsc[i] = cpu_to_le64(((u64)seq.tkip.iv32 << 16) | + seq.tkip.iv16); + } + + data->have_rsc = true; + break; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: /* - * The D3 firmware hardcodes the key offset 0 as the key it - * uses to transmit packets to the AP, i.e. the PTK. + * For non-QoS this relies on the fact that both the uCode and + * mac80211/our RX code use TID 0 for checking the PN. */ - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - mvm->ptk_ivlen = key->iv_len; - mvm->ptk_icvlen = key->icv_len; - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0); + if (sta) { + struct iwl_mvm_sta *mvmsta; + struct iwl_mvm_key_pn *ptk_pn; + const u8 *pn; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + rcu_read_lock(); + ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]); + if (WARN_ON(!ptk_pn)) { + rcu_read_unlock(); + break; + } + + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i, + mvm->trans->num_rx_queues); + rsc[i] = cpu_to_le64((u64)pn[5] | + ((u64)pn[4] << 8) | + ((u64)pn[3] << 16) | + ((u64)pn[2] << 24) | + ((u64)pn[1] << 32) | + ((u64)pn[0] << 40)); + } + + rcu_read_unlock(); } else { - /* - * firmware only supports TSC/RSC for a single key, - * so if there are multiple keep overwriting them - * with new ones -- this relies on mac80211 doing - * list_add_tail(). - */ - mvm->gtk_ivlen = key->iv_len; - mvm->gtk_icvlen = key->icv_len; - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1); + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + u8 *pn = seq.ccmp.pn; + + ieee80211_get_key_rx_seq(key, i, &seq); + rsc[i] = cpu_to_le64((u64)pn[5] | + ((u64)pn[4] << 8) | + ((u64)pn[3] << 16) | + ((u64)pn[2] << 24) | + ((u64)pn[1] << 32) | + ((u64)pn[0] << 40)); + } } - mutex_unlock(&mvm->mutex); - data->error = ret != 0; + data->have_rsc = true; + break; + } +} + +static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_TSC_RSC_PARAM, + IWL_FW_CMD_VER_UNKNOWN); + int ret; + + if (ver == 5) { + struct wowlan_key_rsc_v5_data data = {}; + int i; + + data.rsc = kmalloc(sizeof(*data.rsc), GFP_KERNEL); + if (!data.rsc) + return -ENOMEM; + + memset(data.rsc, 0xff, sizeof(*data.rsc)); + + for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++) + data.rsc->mcast_key_id_map[i] = + IWL_MCAST_KEY_MAP_INVALID; + data.rsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id); + + ieee80211_iter_keys(mvm->hw, vif, + iwl_mvm_wowlan_get_rsc_v5_data, + &data); + + if (data.have_rsc) + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, + CMD_ASYNC, sizeof(*data.rsc), + data.rsc); + else + ret = 0; + kfree(data.rsc); + } else if (ver == 4 || ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { + struct wowlan_key_rsc_tsc_data data = {}; + int size; + + data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL); + if (!data.rsc_tsc) + return -ENOMEM; + + if (ver == 4) { + size = sizeof(*data.rsc_tsc); + data.rsc_tsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id); + } else { + /* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */ + size = sizeof(data.rsc_tsc->params); + } + + ieee80211_iter_keys(mvm->hw, vif, + iwl_mvm_wowlan_get_rsc_tsc_data, + &data); + + if (data.have_rsc_tsc) + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, + CMD_ASYNC, size, + data.rsc_tsc); + else + ret = 0; + kfree(data.rsc_tsc); + } else { + ret = 0; + WARN_ON_ONCE(1); + } + + return ret; +} + +struct wowlan_key_tkip_data { + struct iwl_wowlan_tkip_params_cmd tkip; + bool have_tkip_keys; +}; + +static void iwl_mvm_wowlan_get_tkip_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct wowlan_key_tkip_data *data = _data; + struct iwl_p1k_cache *rx_p1ks; + u8 *rx_mic_key; + struct ieee80211_key_seq seq; + u32 cur_rx_iv32 = 0; + u16 p1k[IWL_P1K_SIZE]; + int i; + + switch (key->cipher) { + default: + break; + case WLAN_CIPHER_SUITE_TKIP: + if (sta) { + u64 pn64; + + rx_p1ks = data->tkip.rx_uni; + + pn64 = atomic64_read(&key->tx_pn); + + ieee80211_get_tkip_p1k_iv(key, TKIP_PN_TO_IV32(pn64), + p1k); + iwl_mvm_convert_p1k(p1k, data->tkip.tx.p1k); + + memcpy(data->tkip.mic_keys.tx, + &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + IWL_MIC_KEY_SIZE); + + rx_mic_key = data->tkip.mic_keys.rx_unicast; + } else { + rx_p1ks = data->tkip.rx_multi; + rx_mic_key = data->tkip.mic_keys.rx_mcast; + } + + for (i = 0; i < IWL_NUM_RSC; i++) { + /* wrapping isn't allowed, AP must rekey */ + if (seq.tkip.iv32 > cur_rx_iv32) + cur_rx_iv32 = seq.tkip.iv32; + } + + ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, + cur_rx_iv32, p1k); + iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k); + ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, + cur_rx_iv32 + 1, p1k); + iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k); + + memcpy(rx_mic_key, + &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + IWL_MIC_KEY_SIZE); + + data->have_tkip_keys = true; + break; + } +} + +struct wowlan_key_gtk_type_iter { + struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; +}; + +static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct wowlan_key_gtk_type_iter *data = _data; + + switch (key->cipher) { + default: + return; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_GCMP); + return; + case WLAN_CIPHER_SUITE_AES_CMAC: + data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_CCM); + return; + case WLAN_CIPHER_SUITE_CCMP: + if (!sta) + data->kek_kck_cmd->gtk_cipher = + cpu_to_le32(STA_KEY_FLG_CCM); + break; + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + if (!sta) + data->kek_kck_cmd->gtk_cipher = + cpu_to_le32(STA_KEY_FLG_GCMP); + break; } } @@ -713,109 +981,81 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, } static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 cmd_flags) + struct ieee80211_vif *vif) { - struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; - struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd; - struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - struct wowlan_key_data key_data = { - .configure_keys = !unified, - .use_rsc_tsc = false, - .tkip = &tkip_cmd, - .use_tkip = false, - .kek_kck_cmd = _kek_kck_cmd, - }; + struct wowlan_key_reprogram_data key_data = {}; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; u8 cmd_ver; size_t cmd_size; - key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); - if (!key_data.rsc_tsc) - return -ENOMEM; - - /* - * if we have to configure keys, call ieee80211_iter_keys(), - * as we need non-atomic context in order to take the - * required locks. - */ - /* - * Note that currently we don't propagate cmd_flags - * to the iterator. In case of key_data.configure_keys, - * all the configured commands are SYNC, and - * iwl_mvm_wowlan_program_keys() will take care of - * locking/unlocking mvm->mutex. - */ - ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_program_keys, - &key_data); + if (!unified) { + /* + * if we have to configure keys, call ieee80211_iter_keys(), + * as we need non-atomic context in order to take the + * required locks. + */ + /* + * Note that currently we don't use CMD_ASYNC in the iterator. + * In case of key_data.configure_keys, all the configured + * commands are SYNC, and iwl_mvm_wowlan_program_keys() will + * take care of locking/unlocking mvm->mutex. + */ + ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_program_keys, + &key_data); - if (key_data.error) { - ret = -EIO; - goto out; + if (key_data.error) + return -EIO; } - if (key_data.use_rsc_tsc) { - int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, - WOWLAN_TSC_RSC_PARAM, - IWL_FW_CMD_VER_UNKNOWN); - int size; - - if (ver == 4) { - size = sizeof(*key_data.rsc_tsc); - key_data.rsc_tsc->sta_id = - cpu_to_le32(mvmvif->ap_sta_id); - - } else if (ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { - size = sizeof(key_data.rsc_tsc->params); - } else { - ret = 0; - WARN_ON_ONCE(1); - goto out; - } - - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, - cmd_flags, - size, - key_data.rsc_tsc); - - if (ret) - goto out; - } + ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif); + if (ret) + return ret; - if (key_data.use_tkip && - !fw_has_api(&mvm->fw->ucode_capa, + if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TKIP_MIC_KEYS)) { int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, WOWLAN_TKIP_PARAM, IWL_FW_CMD_VER_UNKNOWN); + struct wowlan_key_tkip_data tkip_data = {}; int size; if (ver == 2) { - size = sizeof(tkip_cmd); - key_data.tkip->sta_id = + size = sizeof(tkip_data.tkip); + tkip_data.tkip.sta_id = cpu_to_le32(mvmvif->ap_sta_id); } else if (ver == 1 || ver == IWL_FW_CMD_VER_UNKNOWN) { size = sizeof(struct iwl_wowlan_tkip_params_cmd_ver_1); } else { - ret = -EINVAL; WARN_ON_ONCE(1); - goto out; + return -EINVAL; } - /* send relevant data according to CMD version */ - ret = iwl_mvm_send_cmd_pdu(mvm, - WOWLAN_TKIP_PARAM, - cmd_flags, size, - &tkip_cmd); - if (ret) - goto out; + ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_tkip_data, + &tkip_data); + + if (tkip_data.have_tkip_keys) { + /* send relevant data according to CMD version */ + ret = iwl_mvm_send_cmd_pdu(mvm, + WOWLAN_TKIP_PARAM, + CMD_ASYNC, size, + &tkip_data.tkip); + if (ret) + return ret; + } } /* configure rekey data only if offloaded rekey is supported (d3) */ if (mvmvif->rekey_data.valid) { + struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; + struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = + &kek_kck_cmd; + struct wowlan_key_gtk_type_iter gtk_type_data = { + .kek_kck_cmd = _kek_kck_cmd, + }; + cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, WOWLAN_KEK_KCK_MATERIAL, @@ -824,6 +1064,9 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, cmd_ver != IWL_FW_CMD_VER_UNKNOWN)) return -EINVAL; + ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_gtk_type_iter, + >k_type_data); + memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, mvmvif->rekey_data.kck_len); kek_kck_cmd.kck_len = cpu_to_le16(mvmvif->rekey_data.kck_len); @@ -851,17 +1094,13 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, IWL_DEBUG_WOWLAN(mvm, "setting akm %d\n", mvmvif->rekey_data.akm); - ret = iwl_mvm_send_cmd_pdu(mvm, - WOWLAN_KEK_KCK_MATERIAL, cmd_flags, - cmd_size, - _kek_kck_cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_KEK_KCK_MATERIAL, + CMD_ASYNC, cmd_size, _kek_kck_cmd); if (ret) - goto out; + return ret; } - ret = 0; -out: - kfree(key_data.rsc_tsc); - return ret; + + return 0; } static int @@ -893,7 +1132,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, * that isn't really a problem though. */ mutex_unlock(&mvm->mutex); - ret = iwl_mvm_wowlan_config_key_params(mvm, vif, CMD_ASYNC); + ret = iwl_mvm_wowlan_config_key_params(mvm, vif); mutex_lock(&mvm->mutex); if (ret) return ret; @@ -1694,9 +1933,12 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) status->gtk[0] = v7->gtk[0]; status->igtk[0] = v7->igtk[0]; - } else if (notif_ver == 9 || notif_ver == 10) { + } else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) { struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; + /* these three command versions have same layout and size, the + * difference is only in a few not used (reserved) fields. + */ status = iwl_mvm_parse_wowlan_status_common_v9(mvm, cmd.resp_pkt->data, len); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 95f883aba148..5dc39fbb74d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -305,7 +305,6 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, int pos = 0; int bufsz = sizeof(buf); int tbl_idx; - u8 *value; if (!iwl_mvm_firmware_running(mvm)) return -EIO; @@ -321,16 +320,18 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, pos = scnprintf(buf, bufsz, "SAR geographic profile disabled\n"); } else { - value = &mvm->fwrt.geo_profiles[tbl_idx - 1].values[0]; - pos += scnprintf(buf + pos, bufsz - pos, "Use geographic profile %d\n", tbl_idx); pos += scnprintf(buf + pos, bufsz - pos, "2.4GHz:\n\tChain A offset: %hhu dBm\n\tChain B offset: %hhu dBm\n\tmax tx power: %hhu dBm\n", - value[1], value[2], value[0]); + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].chains[0], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].chains[1], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].max); pos += scnprintf(buf + pos, bufsz - pos, "5.2GHz:\n\tChain A offset: %hhu dBm\n\tChain B offset: %hhu dBm\n\tmax tx power: %hhu dBm\n", - value[4], value[5], value[3]); + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].chains[0], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].chains[1], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].max); } mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 59cef0d89a6d..03e5bf5cb909 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -754,6 +754,33 @@ iwl_mvm_ftm_set_ndp_params(struct iwl_mvm *mvm, target->i2r_max_total_ltf = IWL_MVM_FTM_I2R_MAX_TOTAL_LTF; } +static int +iwl_mvm_ftm_put_target_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request_peer *peer, + struct iwl_tof_range_req_ap_entry_v8 *target) +{ + u32 flags; + int ret = iwl_mvm_ftm_put_target_v7(mvm, vif, peer, (void *)target); + + if (ret) + return ret; + + iwl_mvm_ftm_set_ndp_params(mvm, target); + + /* + * If secure LTF is turned off, replace the flag with PMF only + */ + flags = le32_to_cpu(target->initiator_ap_flags); + if ((flags & IWL_INITIATOR_AP_FLAGS_SECURED) && + !IWL_MVM_FTM_INITIATOR_SECURE_LTF) { + flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; + flags |= IWL_INITIATOR_AP_FLAGS_PMF; + target->initiator_ap_flags = cpu_to_le32(flags); + } + + return 0; +} + static int iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_pmsr_request *req) @@ -773,24 +800,53 @@ static int iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm, for (i = 0; i < cmd.num_of_ap; i++) { struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; struct iwl_tof_range_req_ap_entry_v8 *target = &cmd.ap[i]; - u32 flags; - err = iwl_mvm_ftm_put_target_v7(mvm, vif, peer, (void *)target); + err = iwl_mvm_ftm_put_target_v8(mvm, vif, peer, target); if (err) return err; + } - iwl_mvm_ftm_set_ndp_params(mvm, target); - - /* - * If secure LTF is turned off, replace the flag with PMF only - */ - flags = le32_to_cpu(target->initiator_ap_flags); - if ((flags & IWL_INITIATOR_AP_FLAGS_SECURED) && - !IWL_MVM_FTM_INITIATOR_SECURE_LTF) { - flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; - flags |= IWL_INITIATOR_AP_FLAGS_PMF; - target->initiator_ap_flags = cpu_to_le32(flags); + return iwl_mvm_ftm_send_cmd(mvm, &hcmd); +} + +static int iwl_mvm_ftm_start_v13(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) +{ + struct iwl_tof_range_req_cmd_v13 cmd; + struct iwl_host_cmd hcmd = { + .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), + .dataflags[0] = IWL_HCMD_DFL_DUP, + .data[0] = &cmd, + .len[0] = sizeof(cmd), + }; + u8 i; + int err; + + iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req); + + for (i = 0; i < cmd.num_of_ap; i++) { + struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; + struct iwl_tof_range_req_ap_entry_v9 *target = &cmd.ap[i]; + + err = iwl_mvm_ftm_put_target_v8(mvm, vif, peer, (void *)target); + if (err) + return err; + + if (peer->ftm.trigger_based || peer->ftm.non_trigger_based) + target->bss_color = peer->ftm.bss_color; + + if (peer->ftm.non_trigger_based) { + target->min_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR); + target->burst_period = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR); + } else { + target->min_time_between_msr = cpu_to_le16(0); } + + target->band = + iwl_mvm_phy_band_from_nl80211(peer->chandef.chan->band); } return iwl_mvm_ftm_send_cmd(mvm, &hcmd); @@ -814,6 +870,9 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_FW_CMD_VER_UNKNOWN); switch (cmd_ver) { + case 13: + err = iwl_mvm_ftm_start_v13(mvm, vif, req); + break; case 12: err = iwl_mvm_ftm_start_v12(mvm, vif, req); break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 5a249ea97eb2..eba5433c2626 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include <net/cfg80211.h> #include <linux/etherdevice.h> @@ -77,7 +77,7 @@ static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, static void iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm *mvm, - struct iwl_tof_responder_config_cmd_v8 *cmd) + struct iwl_tof_responder_config_cmd_v9 *cmd) { /* Up to 2 R2I STS are allowed on the responder */ u32 r2i_max_sts = IWL_MVM_FTM_R2I_MAX_STS < 2 ? @@ -104,7 +104,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, * field interpretation is different), so the same struct can be use * for all cases. */ - struct iwl_tof_responder_config_cmd_v8 cmd = { + struct iwl_tof_responder_config_cmd_v9 cmd = { .channel_num = chandef->chan->hw_value, .cmd_valid_fields = cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | @@ -115,10 +115,27 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, TOF_RESPONDER_CONFIG_CMD, 6); int err; + int cmd_size; lockdep_assert_held(&mvm->mutex); -if (cmd_ver == 8) + /* Use a default of bss_color=1 for now */ + if (cmd_ver == 9) { + cmd.cmd_valid_fields |= + cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR | + IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR); + cmd.bss_color = 1; + cmd.min_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR); + cmd.max_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR); + cmd_size = sizeof(struct iwl_tof_responder_config_cmd_v9); + } else { + /* All versions up to version 8 have the same size */ + cmd_size = sizeof(struct iwl_tof_responder_config_cmd_v8); + } + + if (cmd_ver >= 8) iwl_mvm_ftm_responder_set_ndp(mvm, &cmd); if (cmd_ver >= 7) @@ -137,7 +154,7 @@ if (cmd_ver == 8) return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD, LOCATION_GROUP, 0), - 0, sizeof(cmd), &cmd); + 0, cmd_size, &cmd); } static int diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 38fd5886af2d..74404c96063b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -743,7 +743,8 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) /* all structs have the same common part, add it */ len += sizeof(cmd.common); - ret = iwl_sar_select_profile(&mvm->fwrt, per_chain, ACPI_SAR_NUM_TABLES, + ret = iwl_sar_select_profile(&mvm->fwrt, per_chain, + IWL_NUM_CHAIN_TABLES, n_subbands, prof_a, prof_b); /* return on error or if the profile is disabled (positive number) */ @@ -1057,16 +1058,7 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) { - int ret; - - ret = iwl_mvm_get_ppag_table(mvm); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "PPAG BIOS table invalid or unavailable. (%d)\n", - ret); - return 0; - } - + /* no need to read the table, done in INIT stage */ if (!dmi_check_system(dmi_ppag_approved_list)) { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is not in the approved list, disabling PPAG.\n", @@ -1191,12 +1183,65 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) ret); } } + +void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) +{ + int ret; + + /* read PPAG table */ + ret = iwl_mvm_get_ppag_table(mvm); + if (ret < 0) { + IWL_DEBUG_RADIO(mvm, + "PPAG BIOS table invalid or unavailable. (%d)\n", + ret); + } + + /* read SAR tables */ + ret = iwl_sar_get_wrds_table(&mvm->fwrt); + if (ret < 0) { + IWL_DEBUG_RADIO(mvm, + "WRDS SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* + * If not available, don't fail and don't bother with EWRD and + * WGDS */ + + if (!iwl_sar_get_wgds_table(&mvm->fwrt)) { + /* + * If basic SAR is not available, we check for WGDS, + * which should *not* be available either. If it is + * available, issue an error, because we can't use SAR + * Geo without basic SAR. + */ + IWL_ERR(mvm, "BIOS contains WGDS but no WRDS\n"); + } + + } else { + ret = iwl_sar_get_ewrd_table(&mvm->fwrt); + /* if EWRD is not available, we can still use + * WRDS, so don't fail */ + if (ret < 0) + IWL_DEBUG_RADIO(mvm, + "EWRD SAR BIOS table invalid or unavailable. (%d)\n", + ret); + + /* read geo SAR table */ + if (iwl_sar_geo_support(&mvm->fwrt)) { + ret = iwl_sar_get_wgds_table(&mvm->fwrt); + if (ret < 0) + IWL_DEBUG_RADIO(mvm, + "Geo SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* we don't fail if the table is not available */ + } + } +} #else /* CONFIG_ACPI */ inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { - return -ENOENT; + return 1; } inline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) @@ -1231,6 +1276,10 @@ static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { return DSM_VALUE_RFI_DISABLE; } + +void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) +{ +} #endif /* CONFIG_ACPI */ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) @@ -1286,27 +1335,6 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) static int iwl_mvm_sar_init(struct iwl_mvm *mvm) { - int ret; - - ret = iwl_sar_get_wrds_table(&mvm->fwrt); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "WRDS SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* - * If not available, don't fail and don't bother with EWRD. - * Return 1 to tell that we can't use WGDS either. - */ - return 1; - } - - ret = iwl_sar_get_ewrd_table(&mvm->fwrt); - /* if EWRD is not available, we can still use WRDS, so don't fail */ - if (ret < 0) - IWL_DEBUG_RADIO(mvm, - "EWRD SAR BIOS table invalid or unavailable. (%d)\n", - ret); - return iwl_mvm_sar_select_profile(mvm, 1, 1); } @@ -1542,19 +1570,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; ret = iwl_mvm_sar_init(mvm); - if (ret == 0) { + if (ret == 0) ret = iwl_mvm_sar_geo_init(mvm); - } else if (ret == -ENOENT && !iwl_sar_get_wgds_table(&mvm->fwrt)) { - /* - * If basic SAR is not available, we check for WGDS, - * which should *not* be available either. If it is - * available, issue an error, because we can't use SAR - * Geo without basic SAR. - */ - IWL_ERR(mvm, "BIOS contains WGDS but no WRDS\n"); - } - - if (ret < 0) + else if (ret < 0) goto error; iwl_mvm_tas_init(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index fd5e08961651..fd352b2624a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -647,12 +647,14 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) { cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX); - if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT) { + if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT) ctxt_sta->data_policy |= cpu_to_le32(TWT_SUPPORTED); - if (vif->bss_conf.twt_protected) - ctxt_sta->data_policy |= - cpu_to_le32(PROTECTED_TWT_SUPPORTED); - } + if (vif->bss_conf.twt_protected) + ctxt_sta->data_policy |= + cpu_to_le32(PROTECTED_TWT_SUPPORTED); + if (vif->bss_conf.twt_broadcast) + ctxt_sta->data_policy |= + cpu_to_le32(BROADCAST_TWT_SUPPORTED); } @@ -1005,8 +1007,10 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, return -ENOMEM; #ifdef CONFIG_IWLWIFI_DEBUGFS - if (mvm->beacon_inject_active) + if (mvm->beacon_inject_active) { + dev_kfree_skb(beacon); return -EBUSY; + } #endif ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon); @@ -1427,14 +1431,34 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); unsigned int pkt_len = iwl_rx_packet_payload_len(pkt); - struct iwl_stored_beacon_notif *sb = (void *)pkt->data; + struct iwl_stored_beacon_notif_common *sb = (void *)pkt->data; struct ieee80211_rx_status rx_status; struct sk_buff *skb; + u8 *data; u32 size = le32_to_cpu(sb->byte_count); + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, PROT_OFFLOAD_GROUP, + STORED_BEACON_NTF, 0); - if (size == 0 || pkt_len < struct_size(sb, data, size)) + if (size == 0) return; + /* handle per-version differences */ + if (ver <= 2) { + struct iwl_stored_beacon_notif_v2 *sb_v2 = (void *)pkt->data; + + if (pkt_len < struct_size(sb_v2, data, size)) + return; + + data = sb_v2->data; + } else { + struct iwl_stored_beacon_notif_v3 *sb_v3 = (void *)pkt->data; + + if (pkt_len < struct_size(sb_v3, data, size)) + return; + + data = sb_v3->data; + } + skb = alloc_skb(size, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); @@ -1455,7 +1479,7 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, rx_status.band); /* copy the data */ - skb_put_data(skb, sb->data, size); + skb_put_data(skb, data, size); memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); /* pass it as regular rx to mac80211 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 70ebecb73c24..3a4585222d6d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -390,7 +390,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (mvm->trans->max_skb_frags) hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG; - hw->queues = IEEE80211_MAX_QUEUES; + hw->queues = IEEE80211_NUM_ACS; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | IEEE80211_RADIOTAP_MCS_HAVE_STBC; @@ -762,11 +762,11 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) goto drop; - /* treat non-bufferable MMPDUs on AP interfaces as broadcast */ - if ((info->control.vif->type == NL80211_IFTYPE_AP || - info->control.vif->type == NL80211_IFTYPE_ADHOC) && - ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) + /* + * bufferable MMPDUs or MMPDUs on STA interfaces come via TXQs + * so we treat the others as broadcast + */ + if (ieee80211_is_mgmt(hdr->frame_control)) sta = NULL; /* If there is no sta, and it's not offchannel - send through AP */ @@ -2440,6 +2440,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_DEBUG_MAC80211(mvm, "arp filter changed\n"); iwl_mvm_configure_bcast_filter(mvm); } + + if (changes & BSS_CHANGED_BANDWIDTH) + iwl_mvm_apply_fw_smps_request(vif); } static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, @@ -2987,16 +2990,20 @@ static void iwl_mvm_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, void *_data) { struct iwl_mvm_he_obss_narrow_bw_ru_data *data = _data; + const struct cfg80211_bss_ies *ies; const struct element *elem; - elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, bss->ies->data, - bss->ies->len); + rcu_read_lock(); + ies = rcu_dereference(bss->ies); + elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, ies->data, + ies->len); if (!elem || elem->datalen < 10 || !(elem->data[10] & WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) { data->tolerated = false; } + rcu_read_unlock(); } static void iwl_mvm_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, @@ -5035,22 +5042,14 @@ static void iwl_mvm_event_mlme_callback_ini(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const struct ieee80211_mlme_event *mlme) { - if (mlme->data == ASSOC_EVENT && (mlme->status == MLME_DENIED || - mlme->status == MLME_TIMEOUT)) { + if ((mlme->data == ASSOC_EVENT || mlme->data == AUTH_EVENT) && + (mlme->status == MLME_DENIED || mlme->status == MLME_TIMEOUT)) { iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_ASSOC_FAILED, NULL); return; } - if (mlme->data == AUTH_EVENT && (mlme->status == MLME_DENIED || - mlme->status == MLME_TIMEOUT)) { - iwl_dbg_tlv_time_point(&mvm->fwrt, - IWL_FW_INI_TIME_POINT_EAPOL_FAILED, - NULL); - return; - } - if (mlme->data == DEAUTH_RX_EVENT || mlme->data == DEAUTH_TX_EVENT) { iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_DEASSOC, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b50942f28bb7..f877d86b038e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -431,8 +431,6 @@ struct iwl_mvm_vif { static inline struct iwl_mvm_vif * iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) { - if (!vif) - return NULL; return (void *)vif->drv_priv; } @@ -2045,6 +2043,7 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm); +void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 7fb4e618f76e..da705fcaf0fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2019 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -416,7 +416,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = MCC_UPDATE_CMD, - .flags = CMD_WANT_SKB, + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, .data = { &mcc_update_cmd }, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 20e8d343a950..6f60018feed1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -78,7 +78,6 @@ module_exit(iwl_mvm_exit); static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - struct iwl_trans_debug *dbg = &mvm->trans->dbg; u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; u32 phy_config = iwl_mvm_get_phy_config(mvm); @@ -115,10 +114,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000) reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; - if (iwl_fw_dbg_is_d3_debug_enabled(&mvm->fwrt) || - (iwl_trans_dbg_ini_valid(mvm->trans) && - dbg->fw_mon_cfg[IWL_FW_INI_ALLOCATION_ID_INTERNAL].buf_location) - ) + if (iwl_fw_dbg_is_d3_debug_enabled(&mvm->fwrt)) reg_val |= CSR_HW_IF_CONFIG_REG_D3_DEBUG; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, @@ -214,11 +210,14 @@ void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; + enum ieee80211_smps_mode mode = IEEE80211_SMPS_AUTOMATIC; - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, - mvm->fw_static_smps_request ? - IEEE80211_SMPS_STATIC : - IEEE80211_SMPS_AUTOMATIC); + if (mvm->fw_static_smps_request && + vif->bss_conf.chandef.width == NL80211_CHAN_WIDTH_160 && + vif->bss_conf.he_support) + mode = IEEE80211_SMPS_STATIC; + + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, mode); } static void iwl_mvm_intf_dual_chain_req(void *data, u8 *mac, @@ -374,7 +373,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { struct iwl_mfu_assert_dump_notif), RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF, iwl_mvm_rx_stored_beacon_notif, RX_HANDLER_SYNC, - struct iwl_stored_beacon_notif), + struct iwl_stored_beacon_notif_v2), RX_HANDLER_GRP(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF, iwl_mvm_mu_mimo_grp_notif, RX_HANDLER_SYNC, struct iwl_mu_group_mgmt_notif), @@ -693,11 +692,16 @@ static int iwl_mvm_start_get_nvm(struct iwl_mvm *mvm) if (ret && ret != -ERFKILL) iwl_fw_dbg_error_collect(&mvm->fwrt, FW_DBG_TRIGGER_DRIVER); + if (!ret && iwl_mvm_is_lar_supported(mvm)) { + mvm->hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; + ret = iwl_mvm_init_mcc(mvm); + } if (!iwlmvm_mod_params.init_dbg || !ret) iwl_mvm_stop_device(mvm); mutex_unlock(&mvm->mutex); + rtnl_unlock(); if (ret < 0) IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); @@ -772,6 +776,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm, dbgfs_dir); + iwl_mvm_get_acpi_tables(mvm); + mvm->init_status = 0; if (iwl_mvm_has_new_rx_api(mvm)) { @@ -792,10 +798,26 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0; - mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; - mvm->snif_queue = IWL_MVM_DQA_INJECT_MONITOR_QUEUE; - mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; - mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; + if (iwl_mvm_has_new_tx_api(mvm)) { + /* + * If we have the new TX/queue allocation API initialize them + * all to invalid numbers. We'll rewrite the ones that we need + * later, but that doesn't happen for all of them all of the + * time (e.g. P2P Device is optional), and if a dynamic queue + * ends up getting number 2 (IWL_MVM_DQA_P2P_DEVICE_QUEUE) then + * iwl_mvm_is_static_queue() erroneously returns true, and we + * might have things getting stuck. + */ + mvm->aux_queue = IWL_MVM_INVALID_QUEUE; + mvm->snif_queue = IWL_MVM_INVALID_QUEUE; + mvm->probe_queue = IWL_MVM_INVALID_QUEUE; + mvm->p2p_dev_queue = IWL_MVM_INVALID_QUEUE; + } else { + mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; + mvm->snif_queue = IWL_MVM_DQA_INJECT_MONITOR_QUEUE; + mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; + mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; + } mvm->sf_state = SF_UNINIT; if (iwl_mvm_has_unified_ucode(mvm)) @@ -1400,7 +1422,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * can't recover this since we're already half suspended. */ if (!mvm->fw_restart && fw_error) { - iwl_fw_error_collect(&mvm->fwrt); + iwl_fw_error_collect(&mvm->fwrt, false); } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { struct iwl_mvm_reprobe *reprobe; @@ -1451,7 +1473,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) } } - iwl_fw_error_collect(&mvm->fwrt); + iwl_fw_error_collect(&mvm->fwrt, false); if (fw_error && mvm->fw_restart > 0) mvm->fw_restart--; @@ -1459,13 +1481,31 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) } } -static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) +static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) iwl_mvm_dump_nic_error_log(mvm); + if (sync) { + iwl_fw_error_collect(&mvm->fwrt, true); + /* + * Currently, the only case for sync=true is during + * shutdown, so just stop in this case. If/when that + * changes, we need to be a bit smarter here. + */ + return; + } + + /* + * If the firmware crashes while we're already considering it + * to be dead then don't ask for a restart, that cannot do + * anything useful anyway. + */ + if (!test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status)) + return; + iwl_mvm_nic_restart(mvm, true); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c index 0b818067067c..44344216a1a9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c @@ -11,7 +11,7 @@ * DDR needs frequency in units of 16.666MHz, so provide FW with the * frequency values in the adjusted format. */ -const static struct iwl_rfi_lut_entry iwl_rfi_table[IWL_RFI_LUT_SIZE] = { +static const struct iwl_rfi_lut_entry iwl_rfi_table[IWL_RFI_LUT_SIZE] = { /* LPDDR4 */ /* frequency 3733MHz */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index c0babb8d5b5c..c12f303cf652 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -69,8 +69,8 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, /* if we are here - this for sure is either CCMP or GCMP */ if (IS_ERR_OR_NULL(sta)) { - IWL_ERR(mvm, - "expected hw-decrypted unicast frame for station\n"); + IWL_DEBUG_DROP(mvm, + "expected hw-decrypted unicast frame for station\n"); return -1; } @@ -279,7 +279,6 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, { struct iwl_mvm_sta *mvmsta; struct iwl_mvm_vif *mvmvif; - u8 fwkeyid = u32_get_bits(status, IWL_RX_MPDU_STATUS_KEY); u8 keyid; struct ieee80211_key_conf *key; u32 len = le16_to_cpu(desc->mpdu_len); @@ -299,6 +298,10 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, if (!ieee80211_is_beacon(hdr->frame_control)) return 0; + /* key mismatch - will also report !MIC_OK but we shouldn't count it */ + if (!(status & IWL_RX_MPDU_STATUS_KEY_VALID)) + return -1; + /* good cases */ if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK && !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) @@ -309,26 +312,36 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, mvmsta = iwl_mvm_sta_from_mac80211(sta); - /* what? */ - if (fwkeyid != 6 && fwkeyid != 7) - return -1; - mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); - key = rcu_dereference(mvmvif->bcn_prot.keys[fwkeyid - 6]); - if (!key) - return -1; + /* + * both keys will have the same cipher and MIC length, use + * whichever one is available + */ + key = rcu_dereference(mvmvif->bcn_prot.keys[0]); + if (!key) { + key = rcu_dereference(mvmvif->bcn_prot.keys[1]); + if (!key) + return -1; + } if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2) return -1; - /* - * See if the key ID matches - if not this may be due to a - * switch and the firmware may erroneously report !MIC_OK. - */ + /* get the real key ID */ keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2]; - if (keyid != fwkeyid) - return -1; + /* and if that's the other key, look it up */ + if (keyid != key->keyidx) { + /* + * shouldn't happen since firmware checked, but be safe + * in case the MIC length is wrong too, for example + */ + if (keyid != 6 && keyid != 7) + return -1; + key = rcu_dereference(mvmvif->bcn_prot.keys[keyid - 6]); + if (!key) + return -1; + } /* Report status to mac80211 */ if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 0368b7101222..d78e436fa8b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1648,7 +1648,7 @@ iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i]; u32 n_aps_flag = iwl_mvm_scan_ch_n_aps_flag(vif_type, - cfg->v2.channel_num); + channels[i]->hw_value); cfg->flags = cpu_to_le32(flags | n_aps_flag); cfg->v2.channel_num = channels[i]->hw_value; @@ -1661,22 +1661,32 @@ iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, } static int -iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm_scan_params *params, - __le32 *cmd_short_ssid, u8 *cmd_bssid, - u8 *scan_ssid_num, u8 *bssid_num) +iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct iwl_scan_probe_params_v4 *pp) { int j, idex_s = 0, idex_b = 0; struct cfg80211_scan_6ghz_params *scan_6ghz_params = params->scan_6ghz_params; + bool hidden_supported = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN); - if (!params->n_6ghz_params) { - for (j = 0; j < params->n_ssids; j++) { - cmd_short_ssid[idex_s++] = - cpu_to_le32(~crc32_le(~0, params->ssids[j].ssid, - params->ssids[j].ssid_len)); - (*scan_ssid_num)++; + for (j = 0; j < params->n_ssids && idex_s < SCAN_SHORT_SSID_MAX_SIZE; + j++) { + if (!params->ssids[j].ssid_len) + continue; + + pp->short_ssid[idex_s] = + cpu_to_le32(~crc32_le(~0, params->ssids[j].ssid, + params->ssids[j].ssid_len)); + + if (hidden_supported) { + pp->direct_scan[idex_s].id = WLAN_EID_SSID; + pp->direct_scan[idex_s].len = params->ssids[j].ssid_len; + memcpy(pp->direct_scan[idex_s].ssid, params->ssids[j].ssid, + params->ssids[j].ssid_len); } - return 0; + idex_s++; } /* @@ -1693,40 +1703,40 @@ iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm_scan_params *params, /* First, try to place the short SSID */ if (scan_6ghz_params[j].short_ssid_valid) { for (k = 0; k < idex_s; k++) { - if (cmd_short_ssid[k] == + if (pp->short_ssid[k] == cpu_to_le32(scan_6ghz_params[j].short_ssid)) break; } if (k == idex_s && idex_s < SCAN_SHORT_SSID_MAX_SIZE) { - cmd_short_ssid[idex_s++] = + pp->short_ssid[idex_s++] = cpu_to_le32(scan_6ghz_params[j].short_ssid); - (*scan_ssid_num)++; } } /* try to place BSSID for the same entry */ for (k = 0; k < idex_b; k++) { - if (!memcmp(&cmd_bssid[ETH_ALEN * k], + if (!memcmp(&pp->bssid_array[k], scan_6ghz_params[j].bssid, ETH_ALEN)) break; } if (k == idex_b && idex_b < SCAN_BSSID_MAX_SIZE) { - memcpy(&cmd_bssid[ETH_ALEN * idex_b++], + memcpy(&pp->bssid_array[idex_b++], scan_6ghz_params[j].bssid, ETH_ALEN); - (*bssid_num)++; } } + + pp->short_ssid_num = idex_s; + pp->bssid_num = idex_b; return 0; } /* TODO: this function can be merged with iwl_mvm_scan_umac_fill_ch_p_v6 */ static void iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, - u32 n_channels, __le32 *cmd_short_ssid, - u8 *cmd_bssid, u8 scan_ssid_num, - u8 bssid_num, + u32 n_channels, + struct iwl_scan_probe_params_v4 *pp, struct iwl_scan_channel_params_v6 *cp, enum nl80211_iftype vif_type) { @@ -1741,7 +1751,7 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, u32 s_ssid_bitmap = 0, bssid_bitmap = 0, flags = 0; u8 j, k, s_max = 0, b_max = 0, n_used_bssid_entries; - bool force_passive, found = false, + bool force_passive, found = false, allow_passive = true, unsolicited_probe_on_chan = false, psc_no_listen = false; cfg->v1.channel_num = params->channels[i]->hw_value; @@ -1766,9 +1776,9 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, scan_6ghz_params[j].unsolicited_probe; psc_no_listen |= scan_6ghz_params[j].psc_no_listen; - for (k = 0; k < scan_ssid_num; k++) { + for (k = 0; k < pp->short_ssid_num; k++) { if (!scan_6ghz_params[j].unsolicited_probe && - le32_to_cpu(cmd_short_ssid[k]) == + le32_to_cpu(pp->short_ssid[k]) == scan_6ghz_params[j].short_ssid) { /* Relevant short SSID bit set */ if (s_ssid_bitmap & BIT(k)) { @@ -1778,7 +1788,10 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, /* * Use short SSID only to create a new - * iteration during channel dwell. + * iteration during channel dwell or in + * case that the short SSID has a + * matching SSID, i.e., scan for hidden + * APs. */ if (n_used_bssid_entries >= 3) { s_ssid_bitmap |= BIT(k); @@ -1786,6 +1799,12 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, n_used_bssid_entries -= 3; found = true; break; + } else if (pp->direct_scan[k].len) { + s_ssid_bitmap |= BIT(k); + s_max++; + found = true; + allow_passive = false; + break; } } } @@ -1793,8 +1812,8 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, if (found) continue; - for (k = 0; k < bssid_num; k++) { - if (!memcmp(&cmd_bssid[ETH_ALEN * k], + for (k = 0; k < pp->bssid_num; k++) { + if (!memcmp(&pp->bssid_array[k], scan_6ghz_params[j].bssid, ETH_ALEN)) { if (!(bssid_bitmap & BIT(k))) { @@ -1849,7 +1868,7 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm_scan_params *params, force_passive |= (unsolicited_probe_on_chan && (s_max > 1 || b_max > 3)); } - if (force_passive || + if ((allow_passive && force_passive) || (!flags && !cfg80211_channel_is_psc(params->channels[i]))) flags |= IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE; @@ -2368,32 +2387,28 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (ret) return ret; - iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, - &bitmap_ssid); if (!params->scan_6ghz) { + iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, + &bitmap_ssid); iwl_mvm_scan_umac_fill_ch_p_v6(mvm, params, vif, - &scan_p->channel_params, bitmap_ssid); + &scan_p->channel_params, bitmap_ssid); return 0; + } else { + pb->preq = params->preq; } + cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS; - ret = iwl_mvm_umac_scan_fill_6g_chan_list(params, pb->short_ssid, - pb->bssid_array[0], - &pb->short_ssid_num, - &pb->bssid_num); + ret = iwl_mvm_umac_scan_fill_6g_chan_list(mvm, params, pb); if (ret) return ret; iwl_mvm_umac_scan_cfg_channels_v6_6g(params, params->n_channels, - pb->short_ssid, - pb->bssid_array[0], - pb->short_ssid_num, - pb->bssid_num, cp, - vif->type); + pb, cp, vif->type); cp->count = params->n_channels; if (!params->n_ssids || (params->n_ssids == 1 && !params->ssids[0].ssid_len)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 9c45a64c5009..a64874c05ced 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -316,8 +316,9 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, } static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int queue, u8 tid, u8 flags) + u16 *queueptr, u8 tid, u8 flags) { + int queue = *queueptr; struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, @@ -326,6 +327,7 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (iwl_mvm_has_new_tx_api(mvm)) { iwl_trans_txq_free(mvm->trans, queue); + *queueptr = IWL_MVM_INVALID_QUEUE; return 0; } @@ -487,6 +489,7 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, u8 sta_id, tid; unsigned long disable_agg_tids = 0; bool same_sta; + u16 queue_tmp = queue; int ret; lockdep_assert_held(&mvm->mutex); @@ -509,7 +512,7 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, iwl_mvm_invalidate_sta_queue(mvm, queue, disable_agg_tids, false); - ret = iwl_mvm_disable_txq(mvm, old_sta, queue, tid, 0); + ret = iwl_mvm_disable_txq(mvm, old_sta, &queue_tmp, tid, 0); if (ret) { IWL_ERR(mvm, "Failed to free inactive queue %d (ret=%d)\n", @@ -1184,6 +1187,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); int queue = -1; + u16 queue_tmp; unsigned long disable_agg_tids = 0; enum iwl_mvm_agg_state queue_state; bool shared_queue = false, inc_ssn; @@ -1332,7 +1336,8 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, return 0; out_err: - iwl_mvm_disable_txq(mvm, sta, queue, tid, 0); + queue_tmp = queue; + iwl_mvm_disable_txq(mvm, sta, &queue_tmp, tid, 0); return ret; } @@ -1779,7 +1784,7 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE) continue; - iwl_mvm_disable_txq(mvm, sta, mvm_sta->tid_data[i].txq_id, i, + iwl_mvm_disable_txq(mvm, sta, &mvm_sta->tid_data[i].txq_id, i, 0); mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE; } @@ -1987,7 +1992,7 @@ static int iwl_mvm_add_int_sta_with_queue(struct iwl_mvm *mvm, int macidx, ret = iwl_mvm_add_int_sta_common(mvm, sta, addr, macidx, maccolor); if (ret) { if (!iwl_mvm_has_new_tx_api(mvm)) - iwl_mvm_disable_txq(mvm, NULL, *queue, + iwl_mvm_disable_txq(mvm, NULL, queue, IWL_MAX_TID_COUNT, 0); return ret; } @@ -2060,7 +2065,7 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA)) return -EINVAL; - iwl_mvm_disable_txq(mvm, NULL, mvm->snif_queue, IWL_MAX_TID_COUNT, 0); + iwl_mvm_disable_txq(mvm, NULL, &mvm->snif_queue, IWL_MAX_TID_COUNT, 0); ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id); if (ret) IWL_WARN(mvm, "Failed sending remove station\n"); @@ -2077,7 +2082,7 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm) if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA)) return -EINVAL; - iwl_mvm_disable_txq(mvm, NULL, mvm->aux_queue, IWL_MAX_TID_COUNT, 0); + iwl_mvm_disable_txq(mvm, NULL, &mvm->aux_queue, IWL_MAX_TID_COUNT, 0); ret = iwl_mvm_rm_sta_common(mvm, mvm->aux_sta.sta_id); if (ret) IWL_WARN(mvm, "Failed sending remove station\n"); @@ -2173,7 +2178,7 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int queue; + u16 *queueptr, queue; lockdep_assert_held(&mvm->mutex); @@ -2182,10 +2187,10 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: - queue = mvm->probe_queue; + queueptr = &mvm->probe_queue; break; case NL80211_IFTYPE_P2P_DEVICE: - queue = mvm->p2p_dev_queue; + queueptr = &mvm->p2p_dev_queue; break; default: WARN(1, "Can't free bcast queue on vif type %d\n", @@ -2193,7 +2198,8 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, return; } - iwl_mvm_disable_txq(mvm, NULL, queue, IWL_MAX_TID_COUNT, 0); + queue = *queueptr; + iwl_mvm_disable_txq(mvm, NULL, queueptr, IWL_MAX_TID_COUNT, 0); if (iwl_mvm_has_new_tx_api(mvm)) return; @@ -2428,7 +2434,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true); - iwl_mvm_disable_txq(mvm, NULL, mvmvif->cab_queue, 0, 0); + iwl_mvm_disable_txq(mvm, NULL, &mvmvif->cab_queue, 0, 0); ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id); if (ret) @@ -3190,6 +3196,20 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, return NULL; } +static int iwl_mvm_pn_cmp(const u8 *pn1, const u8 *pn2, int len) +{ + int i; + + for (i = len - 1; i >= 0; i--) { + if (pn1[i] > pn2[i]) + return 1; + if (pn1[i] < pn2[i]) + return -1; + } + + return 0; +} + static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, u32 sta_id, struct ieee80211_key_conf *key, bool mcast, @@ -3208,6 +3228,9 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, int i, size; bool new_api = fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TKIP_MIC_KEYS); + int api_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + ADD_STA_KEY, + new_api ? 2 : 1); if (sta_id == IWL_MVM_INVALID_STA) return -EINVAL; @@ -3220,7 +3243,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP); - if (new_api) { + if (api_ver >= 2) { memcpy((void *)&u.cmd.tx_mic_key, &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], IWL_MIC_KEY_SIZE); @@ -3241,7 +3264,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_CCMP: key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); memcpy(u.cmd.common.key, key->key, key->keylen); - if (new_api) + if (api_ver >= 2) pn = atomic64_read(&key->tx_pn); break; case WLAN_CIPHER_SUITE_WEP104: @@ -3257,7 +3280,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_GCMP: key_flags |= cpu_to_le16(STA_KEY_FLG_GCMP); memcpy(u.cmd.common.key, key->key, key->keylen); - if (new_api) + if (api_ver >= 2) pn = atomic64_read(&key->tx_pn); break; default: @@ -3274,7 +3297,46 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, u.cmd.common.key_flags = key_flags; u.cmd.common.sta_id = sta_id; - if (new_api) { + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) + i = 0; + else + i = -1; + + for (; i < IEEE80211_NUM_TIDS; i++) { + struct ieee80211_key_seq seq = {}; + u8 _rx_pn[IEEE80211_MAX_PN_LEN] = {}, *rx_pn = _rx_pn; + int rx_pn_len = 8; + /* there's a hole at 2/3 in FW format depending on version */ + int hole = api_ver >= 3 ? 0 : 2; + + ieee80211_get_key_rx_seq(key, i, &seq); + + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { + rx_pn[0] = seq.tkip.iv16; + rx_pn[1] = seq.tkip.iv16 >> 8; + rx_pn[2 + hole] = seq.tkip.iv32; + rx_pn[3 + hole] = seq.tkip.iv32 >> 8; + rx_pn[4 + hole] = seq.tkip.iv32 >> 16; + rx_pn[5 + hole] = seq.tkip.iv32 >> 24; + } else if (key_flags & cpu_to_le16(STA_KEY_FLG_EXT)) { + rx_pn = seq.hw.seq; + rx_pn_len = seq.hw.seq_len; + } else { + rx_pn[0] = seq.ccmp.pn[0]; + rx_pn[1] = seq.ccmp.pn[1]; + rx_pn[2 + hole] = seq.ccmp.pn[2]; + rx_pn[3 + hole] = seq.ccmp.pn[3]; + rx_pn[4 + hole] = seq.ccmp.pn[4]; + rx_pn[5 + hole] = seq.ccmp.pn[5]; + } + + if (iwl_mvm_pn_cmp(rx_pn, (u8 *)&u.cmd.common.rx_secur_seq_cnt, + rx_pn_len) > 0) + memcpy(&u.cmd.common.rx_secur_seq_cnt, rx_pn, + rx_pn_len); + } + + if (api_ver >= 2) { u.cmd.transmit_seq_cnt = cpu_to_le64(pn); size = sizeof(u.cmd); } else { @@ -3411,7 +3473,6 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, u8 key_offset, bool mcast) { - int ret; const u8 *addr; struct ieee80211_key_seq seq; u16 p1k[5]; @@ -3433,30 +3494,19 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, return -EINVAL; } - switch (keyconf->cipher) { - case WLAN_CIPHER_SUITE_TKIP: + if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) { addr = iwl_mvm_get_mac_addr(mvm, vif, sta); /* get phase 1 key from mac80211 */ ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); - ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - seq.tkip.iv32, p1k, 0, key_offset, - mfp); - break; - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - 0, NULL, 0, key_offset, mfp); - break; - default: - ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - 0, NULL, 0, key_offset, mfp); + + return iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, + seq.tkip.iv32, p1k, 0, key_offset, + mfp); } - return ret; + return iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, + 0, NULL, 0, key_offset, mfp); } int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index d3307a11fcac..25af88a3edce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -168,6 +168,16 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, rcu_read_unlock(); } + if (vif->bss_conf.assoc) { + /* + * When not associated, this will be called from + * iwl_mvm_event_mlme_callback_ini() + */ + iwl_dbg_tlv_time_point(&mvm->fwrt, + IWL_FW_INI_TIME_POINT_ASSOC_FAILED, + NULL); + } + iwl_mvm_connection_loss(mvm, vif, errmsg); return true; } @@ -246,6 +256,18 @@ static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm, } } +static void iwl_mvm_p2p_roc_finished(struct iwl_mvm *mvm) +{ + /* + * If the IWL_MVM_STATUS_NEED_FLUSH_P2P is already set, then the + * roc_done_wk is already scheduled or running, so don't schedule it + * again to avoid a race where the roc_done_wk clears this bit after + * it is set here, affecting the next run of the roc_done_wk. + */ + if (!test_and_set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status)) + iwl_mvm_roc_finished(mvm); +} + /* * Handles a FW notification for an event that is known to the driver. * @@ -297,8 +319,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, switch (te_data->vif->type) { case NL80211_IFTYPE_P2P_DEVICE: ieee80211_remain_on_channel_expired(mvm->hw); - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); - iwl_mvm_roc_finished(mvm); + iwl_mvm_p2p_roc_finished(mvm); break; case NL80211_IFTYPE_STATION: /* @@ -674,8 +695,7 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, /* Session protection is still ongoing. Cancel it */ iwl_mvm_cancel_session_protection(mvm, mvmvif, id); if (iftype == NL80211_IFTYPE_P2P_DEVICE) { - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); - iwl_mvm_roc_finished(mvm); + iwl_mvm_p2p_roc_finished(mvm); } } return false; @@ -842,8 +862,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, /* End TE, notify mac80211 */ mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID; ieee80211_remain_on_channel_expired(mvm->hw); - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); - iwl_mvm_roc_finished(mvm); + iwl_mvm_p2p_roc_finished(mvm); } else if (le32_to_cpu(notif->start)) { if (WARN_ON(mvmvif->time_event_data.id != le32_to_cpu(notif->conf_id))) @@ -1004,14 +1023,13 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { iwl_mvm_cancel_session_protection(mvm, mvmvif, mvmvif->time_event_data.id); - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + iwl_mvm_p2p_roc_finished(mvm); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, &mvmvif->time_event_data); + iwl_mvm_roc_finished(mvm); } - iwl_mvm_roc_finished(mvm); - return; } @@ -1025,12 +1043,11 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { iwl_mvm_remove_time_event(mvm, mvmvif, te_data); - set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + iwl_mvm_p2p_roc_finished(mvm); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data); + iwl_mvm_roc_finished(mvm); } - - iwl_mvm_roc_finished(mvm); } void iwl_mvm_remove_csa_period(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 16baee3d52ae..8dc1b8eecb86 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1093,29 +1093,97 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_hr_b0, iwl_ax201_name), + iwl_cfg_bz_a0_hr_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_gf_a0, iwl_ax211_name), + iwl_cfg_bz_a0_gf_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_bz_a0_gf4_a0, iwl_ax211_name), + iwl_cfg_bz_a0_gf4_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_mr_a0, iwl_ax211_name), + iwl_cfg_bz_a0_mr_a0, iwl_bz_name), + +/* SoF with JF2 */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9560_name), + +/* SoF with JF */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9461_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9462_name), /* So with GF */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name) + iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), + +/* So with JF2 */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9560_name), + +/* So with JF */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9461_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9462_name) #endif /* CONFIG_IWLMVM */ }; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index cc550f6ef957..a43e56c7689f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -42,6 +42,7 @@ struct iwl_host_cmd; * struct iwl_rx_mem_buffer * @page_dma: bus address of rxb page * @page: driver's pointer to the rxb page + * @list: list entry for the membuffer * @invalid: rxb is in driver ownership - not owned by HW * @vid: index of this rxb in the global table * @offset: indicates which offset of the page (in bytes) @@ -50,10 +51,10 @@ struct iwl_host_cmd; struct iwl_rx_mem_buffer { dma_addr_t page_dma; struct page *page; - u16 vid; - bool invalid; struct list_head list; u32 offset; + u16 vid; + bool invalid; }; /** @@ -253,6 +254,13 @@ struct cont_rec { }; #endif +enum iwl_pcie_fw_reset_state { + FW_RESET_IDLE, + FW_RESET_REQUESTED, + FW_RESET_OK, + FW_RESET_ERROR, +}; + /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data @@ -404,7 +412,7 @@ struct iwl_trans_pcie { dma_addr_t base_rb_stts_dma; bool fw_reset_handshake; - bool fw_reset_done; + enum iwl_pcie_fw_reset_state fw_reset_state; wait_queue_head_t fw_reset_waitq; char rf_name[32]; @@ -670,19 +678,19 @@ static inline const char *queue_name(struct device *dev, IWL_SHARED_IRQ_FIRST_RSS ? 1 : 0; if (i == 0) - return DRV_NAME ": shared IRQ"; + return DRV_NAME ":shared_IRQ"; return devm_kasprintf(dev, GFP_KERNEL, - DRV_NAME ": queue %d", i + vec); + DRV_NAME ":queue_%d", i + vec); } if (i == 0) - return DRV_NAME ": default queue"; + return DRV_NAME ":default_queue"; if (i == trans_p->alloc_vecs - 1) - return DRV_NAME ": exception"; + return DRV_NAME ":exception"; return devm_kasprintf(dev, GFP_KERNEL, - DRV_NAME ": queue %d", i); + DRV_NAME ":queue_%d", i); } static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 4f6f4b2720f0..8e45eb38304b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -487,6 +487,9 @@ void iwl_pcie_free_rbs_pool(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i; + if (!trans_pcie->rx_pool) + return; + for (i = 0; i < RX_POOL_SIZE(trans_pcie->num_rx_bufs); i++) { if (!trans_pcie->rx_pool[i].page) continue; @@ -1062,7 +1065,7 @@ static int _iwl_pcie_rx_init(struct iwl_trans *trans) INIT_LIST_HEAD(&rba->rbd_empty); spin_unlock_bh(&rba->lock); - /* free all first - we might be reconfigured for a different size */ + /* free all first - we overwrite everything here */ iwl_pcie_free_rbs_pool(trans); for (i = 0; i < RX_QUEUE_SIZE; i++) @@ -1653,7 +1656,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) /* The STATUS_FW_ERROR bit is set in this function. This must happen * before we wake up the command caller, to ensure a proper cleanup. */ - iwl_trans_fw_error(trans); + iwl_trans_fw_error(trans, false); clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); wake_up(&trans->wait_command_queue); @@ -2225,7 +2228,13 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) "Microcode SW error detected. Restarting 0x%X.\n", inta_fh); isr_stats->sw++; - iwl_pcie_irq_handle_error(trans); + /* during FW reset flow report errors from there */ + if (trans_pcie->fw_reset_state == FW_RESET_REQUESTED) { + trans_pcie->fw_reset_state = FW_RESET_ERROR; + wake_up(&trans_pcie->fw_reset_waitq); + } else { + iwl_pcie_irq_handle_error(trans); + } } /* After checking FH register check HW register */ @@ -2293,7 +2302,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) if (inta_hw & MSIX_HW_INT_CAUSES_REG_RESET_DONE) { IWL_DEBUG_ISR(trans, "Reset flow completed\n"); - trans_pcie->fw_reset_done = true; + trans_pcie->fw_reset_state = FW_RESET_OK; wake_up(&trans_pcie->fw_reset_waitq); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index a34009357227..bf0c32a74ca4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -87,7 +87,12 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) * Clear "initialization complete" bit to move adapter from * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ - iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + else + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) @@ -95,7 +100,7 @@ static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; - trans_pcie->fw_reset_done = false; + trans_pcie->fw_reset_state = FW_RESET_REQUESTED; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, @@ -106,10 +111,15 @@ static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) /* wait 200ms */ ret = wait_event_timeout(trans_pcie->fw_reset_waitq, - trans_pcie->fw_reset_done, FW_RESET_TIMEOUT); - if (!ret) + trans_pcie->fw_reset_state != FW_RESET_REQUESTED, + FW_RESET_TIMEOUT); + if (!ret || trans_pcie->fw_reset_state == FW_RESET_ERROR) { IWL_INFO(trans, "firmware didn't ACK the reset - continue anyway\n"); + iwl_trans_fw_error(trans, true); + } + + trans_pcie->fw_reset_state = FW_RESET_IDLE; } void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) @@ -121,9 +131,21 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) if (trans_pcie->is_down) return; - if (trans_pcie->fw_reset_handshake && - trans->state >= IWL_TRANS_FW_STARTED) - iwl_trans_pcie_fw_reset_handshake(trans); + if (trans->state >= IWL_TRANS_FW_STARTED) { + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ); + iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + 5000); + msleep(100); + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_SW_RESET); + } else if (trans_pcie->fw_reset_handshake) { + iwl_trans_pcie_fw_reset_handshake(trans); + } + } trans_pcie->is_down = true; @@ -154,9 +176,17 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) iwl_pcie_ctxt_info_free(trans); /* Make sure (redundant) we've released our request to stay awake */ - iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); + else + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_SW_RESET); + } /* Stop the device, and put it in low power state */ iwl_pcie_gen2_apm_stop(trans, false); @@ -436,7 +466,10 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, iwl_pcie_set_ltr(trans); - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_ROM_START); + else if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_CPU_INIT_RUN, 1); else iwl_write_prph(trans, UREG_CPU_INIT_RUN, 1); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index bee6b4574226..f252680f18e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -449,11 +449,23 @@ void iwl_pcie_apm_stop_master(struct iwl_trans *trans) int ret; /* stop device's busmaster DMA activity */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(trans, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ); + + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + 100); + } else { + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + ret = iwl_poll_bit(trans, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + } + if (ret < 0) IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); @@ -1866,6 +1878,9 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + /* free all first - we might be reconfigured for a different size */ + iwl_pcie_free_rbs_pool(trans); + trans->txqs.cmd.q_id = trans_cfg->cmd_queue; trans->txqs.cmd.fifo = trans_cfg->cmd_fifo; trans->txqs.cmd.wdg_timeout = trans_cfg->cmd_q_wdg_timeout; @@ -1992,15 +2007,24 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans) { int ret; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 write = CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ; + u32 mask = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP; + u32 poll = CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN; spin_lock(&trans_pcie->reg_lock); if (trans_pcie->cmd_hold_nic_awake) goto out; + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + write = CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ; + mask = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; + poll = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; + } + /* this bit wakes up the NIC */ - __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, write); if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); @@ -2024,10 +2048,7 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans) * 5000 series and later (including 1000 series) have non-volatile SRAM, * and do not save/restore SRAM when power cycling. */ - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, poll, mask, 15000); if (unlikely(ret < 0)) { u32 cntrl = iwl_read32(trans, CSR_GP_CNTRL); @@ -2947,8 +2968,8 @@ static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb = rxq->queue[i]; struct iwl_fw_error_dump_rb *rb; - dma_unmap_page(trans->dev, rxb->page_dma, max_len, - DMA_FROM_DEVICE); + dma_sync_single_for_cpu(trans->dev, rxb->page_dma, + max_len, DMA_FROM_DEVICE); rb_len += sizeof(**data) + sizeof(*rb) + max_len; @@ -2957,10 +2978,6 @@ static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans, rb = (void *)(*data)->data; rb->index = cpu_to_le32(i); memcpy(rb->data, page_address(rxb->page), max_len); - /* remap the page for the free benefit */ - rxb->page_dma = dma_map_page(trans->dev, rxb->page, - rxb->offset, max_len, - DMA_FROM_DEVICE); *data = iwl_fw_error_next_data(*data); } @@ -3489,15 +3506,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, pci_set_master(pdev); addr_size = trans->txqs.tfd.addr_size; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(addr_size)); - if (!ret) - ret = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(addr_size)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_size)); if (ret) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!ret) - ret = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); /* both attempts failed: */ if (ret) { dev_err(&pdev->dev, "No suitable DMA available\n"); diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig index c52d9b535623..bd6bf70ece03 100644 --- a/drivers/net/wireless/intersil/Kconfig +++ b/drivers/net/wireless/intersil/Kconfig @@ -16,24 +16,4 @@ source "drivers/net/wireless/intersil/hostap/Kconfig" source "drivers/net/wireless/intersil/orinoco/Kconfig" source "drivers/net/wireless/intersil/p54/Kconfig" -config PRISM54 - tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' - depends on PCI - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - help - This enables support for FullMAC PCI/Cardbus prism54 devices. This - driver is now deprecated in favor for the SoftMAC driver, p54pci. - p54pci supports FullMAC PCI/Cardbus devices as well. - - For more information refer to the p54 wiki: - - http://wireless.wiki.kernel.org/en/users/Drivers/p54 - - Note: You need a motherboard with DMA support to use any of these cards - - When built as module you get the module prism54 - endif # WLAN_VENDOR_INTERSIL diff --git a/drivers/net/wireless/intersil/Makefile b/drivers/net/wireless/intersil/Makefile index aa630e9c3d3d..65281d1b3d85 100644 --- a/drivers/net/wireless/intersil/Makefile +++ b/drivers/net/wireless/intersil/Makefile @@ -2,4 +2,3 @@ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_P54_COMMON) += p54/ -obj-$(CONFIG_PRISM54) += prism54/ diff --git a/drivers/net/wireless/intersil/hostap/hostap.h b/drivers/net/wireless/intersil/hostap/hostap.h index c4b81ff7d7e4..c17ab6dbbb53 100644 --- a/drivers/net/wireless/intersil/hostap/hostap.h +++ b/drivers/net/wireless/intersil/hostap/hostap.h @@ -93,6 +93,7 @@ extern const struct iw_handler_def hostap_iw_handler_def; extern const struct ethtool_ops prism2_ethtool_ops; int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); - +int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, + void __user *data, int cmd); #endif /* HOSTAP_H */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c index 49766b285230..0a376f112db9 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c @@ -3941,7 +3941,8 @@ const struct iw_handler_def hostap_iw_handler_def = .get_wireless_stats = hostap_get_wireless_stats, }; - +/* Private ioctls (iwpriv) that have not yet been converted + * into new wireless extensions API */ int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct iwreq *wrq = (struct iwreq *) ifr; @@ -3953,9 +3954,6 @@ int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) local = iface->local; switch (cmd) { - /* Private ioctls (iwpriv) that have not yet been converted - * into new wireless extensions API */ - case PRISM2_IOCTL_INQUIRE: if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name); @@ -4009,11 +4007,31 @@ int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) wrq->u.ap_addr.sa_data); break; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} +/* Private ioctls that are not used with iwpriv; + * in SIOCDEVPRIVATE range */ +int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, + void __user *data, int cmd) +{ + struct iwreq *wrq = (struct iwreq *)ifr; + struct hostap_interface *iface; + local_info_t *local; + int ret = 0; - /* Private ioctls that are not used with iwpriv; - * in SIOCDEVPRIVATE range */ + iface = netdev_priv(dev); + local = iface->local; + + if (in_compat_syscall()) /* not implemented yet */ + return -EOPNOTSUPP; + switch (cmd) { #ifdef PRISM2_DOWNLOAD_SUPPORT case PRISM2_IOCTL_DOWNLOAD: if (!capable(CAP_NET_ADMIN)) ret = -EPERM; diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c index de97b3304115..54f67b682b6a 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ b/drivers/net/wireless/intersil/hostap/hostap_main.c @@ -797,6 +797,7 @@ static const struct net_device_ops hostap_netdev_ops = { .ndo_open = prism2_open, .ndo_stop = prism2_close, .ndo_do_ioctl = hostap_ioctl, + .ndo_siocdevprivate = hostap_siocdevprivate, .ndo_set_mac_address = prism2_set_mac_address, .ndo_set_rx_mode = hostap_set_multicast_list, .ndo_tx_timeout = prism2_tx_timeout, @@ -809,6 +810,7 @@ static const struct net_device_ops hostap_mgmt_netdev_ops = { .ndo_open = prism2_open, .ndo_stop = prism2_close, .ndo_do_ioctl = hostap_ioctl, + .ndo_siocdevprivate = hostap_siocdevprivate, .ndo_set_mac_address = prism2_set_mac_address, .ndo_set_rx_mode = hostap_set_multicast_list, .ndo_tx_timeout = prism2_tx_timeout, @@ -821,6 +823,7 @@ static const struct net_device_ops hostap_master_ops = { .ndo_open = prism2_open, .ndo_stop = prism2_close, .ndo_do_ioctl = hostap_ioctl, + .ndo_siocdevprivate = hostap_siocdevprivate, .ndo_set_mac_address = prism2_set_mac_address, .ndo_set_rx_mode = hostap_set_multicast_list, .ndo_tx_timeout = prism2_tx_timeout, diff --git a/drivers/net/wireless/intersil/prism54/Makefile b/drivers/net/wireless/intersil/prism54/Makefile deleted file mode 100644 index 4f5572dffb5e..000000000000 --- a/drivers/net/wireless/intersil/prism54/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# $Id: Makefile.k26,v 1.7 2004/01/30 16:24:00 ajfa Exp $ - -prism54-objs := islpci_eth.o islpci_mgt.o \ - isl_38xx.o isl_ioctl.o islpci_dev.o \ - islpci_hotplug.o oid_mgt.o - -obj-$(CONFIG_PRISM54) += prism54.o - diff --git a/drivers/net/wireless/intersil/prism54/isl_38xx.c b/drivers/net/wireless/intersil/prism54/isl_38xx.c deleted file mode 100644 index ae964de347f7..000000000000 --- a/drivers/net/wireless/intersil/prism54/isl_38xx.c +++ /dev/null @@ -1,245 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2002 Intersil Americas Inc. - * Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_ - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/ktime.h> - -#include <linux/uaccess.h> -#include <asm/io.h> - -#include "prismcompat.h" -#include "isl_38xx.h" -#include "islpci_dev.h" -#include "islpci_mgt.h" - -/****************************************************************************** - Device Interface & Control functions -******************************************************************************/ - -/** - * isl38xx_disable_interrupts - disable all interrupts - * @device: pci memory base address - * - * Instructs the device to disable all interrupt reporting by asserting - * the IRQ line. New events may still show up in the interrupt identification - * register located at offset %ISL38XX_INT_IDENT_REG. - */ -void -isl38xx_disable_interrupts(void __iomem *device) -{ - isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); - udelay(ISL38XX_WRITEIO_DELAY); -} - -void -isl38xx_handle_sleep_request(isl38xx_control_block *control_block, - int *powerstate, void __iomem *device_base) -{ - /* device requests to go into sleep mode - * check whether the transmit queues for data and management are empty */ - if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)) - /* data tx queue not empty */ - return; - - if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) - /* management tx queue not empty */ - return; - - /* check also whether received frames are pending */ - if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ)) - /* data rx queue not empty */ - return; - - if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ)) - /* management rx queue not empty */ - return; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "Device going to sleep mode\n"); -#endif - - /* all queues are empty, allow the device to go into sleep mode */ - *powerstate = ISL38XX_PSM_POWERSAVE_STATE; - - /* assert the Sleep interrupt in the Device Interrupt Register */ - isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP, - ISL38XX_DEV_INT_REG); - udelay(ISL38XX_WRITEIO_DELAY); -} - -void -isl38xx_handle_wakeup(isl38xx_control_block *control_block, - int *powerstate, void __iomem *device_base) -{ - /* device is in active state, update the powerstate flag */ - *powerstate = ISL38XX_PSM_ACTIVE_STATE; - - /* now check whether there are frames pending for the card */ - if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ) - && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) - return; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n"); -#endif - - /* either data or management transmit queue has a frame pending - * trigger the device by setting the Update bit in the Device Int reg */ - isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, - ISL38XX_DEV_INT_REG); - udelay(ISL38XX_WRITEIO_DELAY); -} - -void -isl38xx_trigger_device(int asleep, void __iomem *device_base) -{ - u32 reg; - -#if VERBOSE > SHOW_ERROR_MESSAGES - u32 counter = 0; - struct timespec64 current_ts64; - DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n"); -#endif - - /* check whether the device is in power save mode */ - if (asleep) { - /* device is in powersave, trigger the device for wakeup */ -#if VERBOSE > SHOW_ERROR_MESSAGES - ktime_get_real_ts64(¤t_ts64); - DEBUG(SHOW_TRACING, "%lld.%09ld Device wakeup triggered\n", - (s64)current_ts64.tv_sec, current_ts64.tv_nsec); - - DEBUG(SHOW_TRACING, "%lld.%09ld Device register read %08x\n", - (s64)current_ts64.tv_sec, current_ts64.tv_nsec, - readl(device_base + ISL38XX_CTRL_STAT_REG)); -#endif - - reg = readl(device_base + ISL38XX_INT_IDENT_REG); - if (reg == 0xabadface) { -#if VERBOSE > SHOW_ERROR_MESSAGES - ktime_get_real_ts64(¤t_ts64); - DEBUG(SHOW_TRACING, - "%lld.%09ld Device register abadface\n", - (s64)current_ts64.tv_sec, current_ts64.tv_nsec); -#endif - /* read the Device Status Register until Sleepmode bit is set */ - while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG), - (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) { - udelay(ISL38XX_WRITEIO_DELAY); -#if VERBOSE > SHOW_ERROR_MESSAGES - counter++; -#endif - } - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, - "%lld.%09ld Device register read %08x\n", - (s64)current_ts64.tv_sec, current_ts64.tv_nsec, - readl(device_base + ISL38XX_CTRL_STAT_REG)); - ktime_get_real_ts64(¤t_ts64); - DEBUG(SHOW_TRACING, - "%lld.%09ld Device asleep counter %i\n", - (s64)current_ts64.tv_sec, current_ts64.tv_nsec, - counter); -#endif - } - /* assert the Wakeup interrupt in the Device Interrupt Register */ - isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP, - ISL38XX_DEV_INT_REG); - -#if VERBOSE > SHOW_ERROR_MESSAGES - udelay(ISL38XX_WRITEIO_DELAY); - - /* perform another read on the Device Status Register */ - reg = readl(device_base + ISL38XX_CTRL_STAT_REG); - ktime_get_real_ts64(¤t_ts64); - DEBUG(SHOW_TRACING, "%lld.%00ld Device register read %08x\n", - (s64)current_ts64.tv_sec, current_ts64.tv_nsec, reg); -#endif - } else { - /* device is (still) awake */ -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "Device is in active state\n"); -#endif - /* trigger the device by setting the Update bit in the Device Int reg */ - - isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, - ISL38XX_DEV_INT_REG); - } -} - -void -isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) -{ -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n"); -#endif - - /* load the address of the control block in the device */ - isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG); - udelay(ISL38XX_WRITEIO_DELAY); - - /* set the reset bit in the Device Interrupt Register */ - isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG); - udelay(ISL38XX_WRITEIO_DELAY); - - /* enable the interrupt for detecting initialization */ - - /* Note: Do not enable other interrupts here. We want the - * device to have come up first 100% before allowing any other - * interrupts. */ - isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG); - udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ -} - -void -isl38xx_enable_common_interrupts(void __iomem *device_base) -{ - u32 reg; - - reg = ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP | - ISL38XX_INT_IDENT_WAKEUP; - isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); - udelay(ISL38XX_WRITEIO_DELAY); -} - -int -isl38xx_in_queue(isl38xx_control_block *cb, int queue) -{ - const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) - - le32_to_cpu(cb->device_curr_frag[queue])); - - /* determine the amount of fragments in the queue depending on the type - * of the queue, either transmit or receive */ - - BUG_ON(delta < 0); /* driver ptr must be ahead of device ptr */ - - switch (queue) { - /* send queues */ - case ISL38XX_CB_TX_MGMTQ: - BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); - fallthrough; - - case ISL38XX_CB_TX_DATA_LQ: - case ISL38XX_CB_TX_DATA_HQ: - BUG_ON(delta > ISL38XX_CB_TX_QSIZE); - return delta; - - /* receive queues */ - case ISL38XX_CB_RX_MGMTQ: - BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); - return ISL38XX_CB_MGMT_QSIZE - delta; - - case ISL38XX_CB_RX_DATA_LQ: - case ISL38XX_CB_RX_DATA_HQ: - BUG_ON(delta > ISL38XX_CB_RX_QSIZE); - return ISL38XX_CB_RX_QSIZE - delta; - } - BUG(); - return 0; -} diff --git a/drivers/net/wireless/intersil/prism54/isl_38xx.h b/drivers/net/wireless/intersil/prism54/isl_38xx.h deleted file mode 100644 index 69218b8b2b23..000000000000 --- a/drivers/net/wireless/intersil/prism54/isl_38xx.h +++ /dev/null @@ -1,158 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2002 Intersil Americas Inc. - */ - -#ifndef _ISL_38XX_H -#define _ISL_38XX_H - -#include <asm/io.h> -#include <asm/byteorder.h> - -#define ISL38XX_CB_RX_QSIZE 8 -#define ISL38XX_CB_TX_QSIZE 32 - -/* ISL38XX Access Point Specific definitions */ -#define ISL38XX_MAX_WDS_LINKS 8 - -/* ISL38xx Client Specific definitions */ -#define ISL38XX_PSM_ACTIVE_STATE 0 -#define ISL38XX_PSM_POWERSAVE_STATE 1 - -/* ISL38XX Host Interface Definitions */ -#define ISL38XX_PCI_MEM_SIZE 0x02000 -#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000 -#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000 -#define ISL38XX_WRITEIO_DELAY 10 /* in us */ -#define ISL38XX_RESET_DELAY 50 /* in ms */ -#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */ -#define ISL38XX_MAX_WAIT_CYCLES 10 - -/* PCI Memory Area */ -#define ISL38XX_HARDWARE_REG 0x0000 -#define ISL38XX_CARDBUS_CIS 0x0800 -#define ISL38XX_DIRECT_MEM_WIN 0x1000 - -/* Hardware registers */ -#define ISL38XX_DEV_INT_REG 0x0000 -#define ISL38XX_INT_IDENT_REG 0x0010 -#define ISL38XX_INT_ACK_REG 0x0014 -#define ISL38XX_INT_EN_REG 0x0018 -#define ISL38XX_GEN_PURP_COM_REG_1 0x0020 -#define ISL38XX_GEN_PURP_COM_REG_2 0x0024 -#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1 -#define ISL38XX_DIR_MEM_BASE_REG 0x0030 -#define ISL38XX_CTRL_STAT_REG 0x0078 - -/* High end mobos queue up pci writes, the following - * is used to "read" from after a write to force flush */ -#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG - -/** - * isl38xx_w32_flush - PCI iomem write helper - * @base: (host) memory base address of the device - * @val: 32bit value (host order) to write - * @offset: byte offset into @base to write value to - * - * This helper takes care of writing a 32bit datum to the - * specified offset into the device's pci memory space, and making sure - * the pci memory buffers get flushed by performing one harmless read - * from the %ISL38XX_PCI_POSTING_FLUSH offset. - */ -static inline void -isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset) -{ - writel(val, base + offset); - (void) readl(base + ISL38XX_PCI_POSTING_FLUSH); -} - -/* Device Interrupt register bits */ -#define ISL38XX_DEV_INT_RESET 0x0001 -#define ISL38XX_DEV_INT_UPDATE 0x0002 -#define ISL38XX_DEV_INT_WAKEUP 0x0008 -#define ISL38XX_DEV_INT_SLEEP 0x0010 - -/* Interrupt Identification/Acknowledge/Enable register bits */ -#define ISL38XX_INT_IDENT_UPDATE 0x0002 -#define ISL38XX_INT_IDENT_INIT 0x0004 -#define ISL38XX_INT_IDENT_WAKEUP 0x0008 -#define ISL38XX_INT_IDENT_SLEEP 0x0010 -#define ISL38XX_INT_SOURCES 0x001E - -/* Control/Status register bits */ -/* Looks like there are other meaningful bits - 0x20004400 seen in normal operation, - 0x200044db at 'timeout waiting for mgmt response' -*/ -#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 -#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 -#define ISL38XX_CTRL_STAT_RESET 0x10000000 -#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 -#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 -#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 - -/* Control Block definitions */ -#define ISL38XX_CB_RX_DATA_LQ 0 -#define ISL38XX_CB_TX_DATA_LQ 1 -#define ISL38XX_CB_RX_DATA_HQ 2 -#define ISL38XX_CB_TX_DATA_HQ 3 -#define ISL38XX_CB_RX_MGMTQ 4 -#define ISL38XX_CB_TX_MGMTQ 5 -#define ISL38XX_CB_QCOUNT 6 -#define ISL38XX_CB_MGMT_QSIZE 4 -#define ISL38XX_MIN_QTHRESHOLD 4 /* fragments */ - -/* Memory Manager definitions */ -#define MGMT_FRAME_SIZE 1500 /* >= size struct obj_bsslist */ -#define MGMT_TX_FRAME_COUNT 24 /* max 4 + spare 4 + 8 init */ -#define MGMT_RX_FRAME_COUNT 24 /* 4*4 + spare 8 */ -#define MGMT_FRAME_COUNT (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT) -#define CONTROL_BLOCK_SIZE 1024 /* should be enough */ -#define PSM_FRAME_SIZE 1536 -#define PSM_MINIMAL_STATION_COUNT 64 -#define PSM_FRAME_COUNT PSM_MINIMAL_STATION_COUNT -#define PSM_BUFFER_SIZE PSM_FRAME_SIZE * PSM_FRAME_COUNT -#define MAX_TRAP_RX_QUEUE 4 -#define HOST_MEM_BLOCK CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE - -/* Fragment package definitions */ -#define FRAGMENT_FLAG_MF 0x0001 -#define MAX_FRAGMENT_SIZE 1536 - -/* In monitor mode frames have a header. I don't know exactly how big those - * frame can be but I've never seen any frame bigger than 1584... : - */ -#define MAX_FRAGMENT_SIZE_RX 1600 - -typedef struct { - __le32 address; /* physical address on host */ - __le16 size; /* packet size */ - __le16 flags; /* set of bit-wise flags */ -} isl38xx_fragment; - -struct isl38xx_cb { - __le32 driver_curr_frag[ISL38XX_CB_QCOUNT]; - __le32 device_curr_frag[ISL38XX_CB_QCOUNT]; - isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE]; - isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE]; - isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE]; - isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE]; - isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; - isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; -}; - -typedef struct isl38xx_cb isl38xx_control_block; - -/* determine number of entries currently in queue */ -int isl38xx_in_queue(isl38xx_control_block *cb, int queue); - -void isl38xx_disable_interrupts(void __iomem *); -void isl38xx_enable_common_interrupts(void __iomem *); - -void isl38xx_handle_sleep_request(isl38xx_control_block *, int *, - void __iomem *); -void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void __iomem *); -void isl38xx_trigger_device(int, void __iomem *); -void isl38xx_interface_reset(void __iomem *, dma_addr_t); - -#endif /* _ISL_38XX_H */ diff --git a/drivers/net/wireless/intersil/prism54/isl_ioctl.c b/drivers/net/wireless/intersil/prism54/isl_ioctl.c deleted file mode 100644 index 5e5ceafe098b..000000000000 --- a/drivers/net/wireless/intersil/prism54/isl_ioctl.c +++ /dev/null @@ -1,2909 +0,0 @@ -/* - * Copyright (C) 2002 Intersil Americas Inc. - * (C) 2003,2004 Aurelien Alleaume <slts@free.fr> - * (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> - * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <linux/capability.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/if_arp.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/etherdevice.h> - -#include <linux/uaccess.h> - -#include "prismcompat.h" -#include "isl_ioctl.h" -#include "islpci_mgt.h" -#include "isl_oid.h" /* additional types and defs for isl38xx fw */ -#include "oid_mgt.h" - -#include <net/iw_handler.h> /* New driver API */ - -#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */ -#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */ -/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */ -#define KEY_SIZE_TKIP 32 /* TKIP keys */ - -static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, - u8 *wpa_ie, size_t wpa_ie_len); -static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); -static int prism54_set_wpa(struct net_device *, struct iw_request_info *, - __u32 *, char *); - -/* In 500 kbps */ -static const unsigned char scan_rate_list[] = { 2, 4, 11, 22, - 12, 18, 24, 36, - 48, 72, 96, 108 }; - -/** - * prism54_mib_mode_helper - MIB change mode helper function - * @priv: the &struct islpci_private object to modify - * @iw_mode: new mode (%IW_MODE_*) - * - * This is a helper function, hence it does not lock. Make sure - * caller deals with locking *if* necessary. This function sets the - * mode-dependent mib values and does the mapping of the Linux - * Wireless API modes to Device firmware modes. It also checks for - * correct valid Linux wireless modes. - */ -static int -prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) -{ - u32 config = INL_CONFIG_MANUALRUN; - u32 mode, bsstype; - - /* For now, just catch early the Repeater and Secondary modes here */ - if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { - printk(KERN_DEBUG - "%s(): Sorry, Repeater mode and Secondary mode " - "are not yet supported by this driver.\n", __func__); - return -EINVAL; - } - - priv->iw_mode = iw_mode; - - switch (iw_mode) { - case IW_MODE_AUTO: - mode = INL_MODE_CLIENT; - bsstype = DOT11_BSSTYPE_ANY; - break; - case IW_MODE_ADHOC: - mode = INL_MODE_CLIENT; - bsstype = DOT11_BSSTYPE_IBSS; - break; - case IW_MODE_INFRA: - mode = INL_MODE_CLIENT; - bsstype = DOT11_BSSTYPE_INFRA; - break; - case IW_MODE_MASTER: - mode = INL_MODE_AP; - bsstype = DOT11_BSSTYPE_INFRA; - break; - case IW_MODE_MONITOR: - mode = INL_MODE_PROMISCUOUS; - bsstype = DOT11_BSSTYPE_ANY; - config |= INL_CONFIG_RXANNEX; - break; - default: - return -EINVAL; - } - - if (init_wds) - config |= INL_CONFIG_WDS; - mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype); - mgt_set(priv, OID_INL_CONFIG, &config); - mgt_set(priv, OID_INL_MODE, &mode); - - return 0; -} - -/* - * prism54_mib_init - fill MIB cache with defaults - * - * this function initializes the struct given as @mib with defaults, - * of which many are retrieved from the global module parameter - * variables. - */ -void -prism54_mib_init(islpci_private *priv) -{ - u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode; - struct obj_buffer psm_buffer = { - .size = PSM_BUFFER_SIZE, - .addr = priv->device_psm_buffer - }; - - channel = CARD_DEFAULT_CHANNEL; - authen = CARD_DEFAULT_AUTHEN; - wep = CARD_DEFAULT_WEP; - filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */ - dot1x = CARD_DEFAULT_DOT1X; - mlme = CARD_DEFAULT_MLME_MODE; - conformance = CARD_DEFAULT_CONFORMANCE; - power = 127; - mode = CARD_DEFAULT_IW_MODE; - - mgt_set(priv, DOT11_OID_CHANNEL, &channel); - mgt_set(priv, DOT11_OID_AUTHENABLE, &authen); - mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep); - mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); - mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter); - mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x); - mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme); - mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance); - mgt_set(priv, OID_INL_OUTPUTPOWER, &power); - - /* This sets all of the mode-dependent values */ - prism54_mib_mode_helper(priv, mode); -} - -/* this will be executed outside of atomic context thanks to - * schedule_work(), thus we can as well use sleeping semaphore - * locking */ -void -prism54_update_stats(struct work_struct *work) -{ - islpci_private *priv = container_of(work, islpci_private, stats_work); - char *data; - struct obj_bss bss, *bss2; - union oid_res_t r; - - mutex_lock(&priv->stats_lock); - -/* Noise floor. - * I'm not sure if the unit is dBm. - * Note : If we are not connected, this value seems to be irrelevant. */ - - mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); - priv->local_iwstatistics.qual.noise = r.u; - -/* Get the rssi of the link. To do this we need to retrieve a bss. */ - - /* First get the MAC address of the AP we are associated with. */ - mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); - data = r.ptr; - - /* copy this MAC to the bss */ - memcpy(bss.address, data, ETH_ALEN); - kfree(data); - - /* now ask for the corresponding bss */ - mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r); - bss2 = r.ptr; - /* report the rssi and use it to calculate - * link quality through a signal-noise - * ratio */ - priv->local_iwstatistics.qual.level = bss2->rssi; - priv->local_iwstatistics.qual.qual = - bss2->rssi - priv->iwstatistics.qual.noise; - - kfree(bss2); - - /* report that the stats are new */ - priv->local_iwstatistics.qual.updated = 0x7; - -/* Rx : unable to decrypt the MPDU */ - mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r); - priv->local_iwstatistics.discard.code = r.u; - -/* Tx : Max MAC retries num reached */ - mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); - priv->local_iwstatistics.discard.retries = r.u; - - mutex_unlock(&priv->stats_lock); -} - -struct iw_statistics * -prism54_get_wireless_stats(struct net_device *ndev) -{ - islpci_private *priv = netdev_priv(ndev); - - /* If the stats are being updated return old data */ - if (mutex_trylock(&priv->stats_lock)) { - memcpy(&priv->iwstatistics, &priv->local_iwstatistics, - sizeof (struct iw_statistics)); - /* They won't be marked updated for the next time */ - priv->local_iwstatistics.qual.updated = 0; - mutex_unlock(&priv->stats_lock); - } else - priv->iwstatistics.qual.updated = 0; - - /* Update our wireless stats, but do not schedule to often - * (max 1 HZ) */ - if ((priv->stats_timestamp == 0) || - time_after(jiffies, priv->stats_timestamp + 1 * HZ)) { - schedule_work(&priv->stats_work); - priv->stats_timestamp = jiffies; - } - - return &priv->iwstatistics; -} - -static int -prism54_commit(struct net_device *ndev, struct iw_request_info *info, - char *cwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - - /* simply re-set the last set SSID, this should commit most stuff */ - - /* Commit in Monitor mode is not necessary, also setting essid - * in Monitor mode does not make sense and isn't allowed for this - * device's firmware */ - if (priv->iw_mode != IW_MODE_MONITOR) - return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL); - return 0; -} - -static int -prism54_get_name(struct net_device *ndev, struct iw_request_info *info, - char *cwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - char *capabilities; - union oid_res_t r; - int rvalue; - - if (islpci_get_state(priv) < PRV_STATE_INIT) { - strncpy(cwrq, "NOT READY!", IFNAMSIZ); - return 0; - } - rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r); - - switch (r.u) { - case INL_PHYCAP_5000MHZ: - capabilities = "IEEE 802.11a/b/g"; - break; - case INL_PHYCAP_FAA: - capabilities = "IEEE 802.11b/g - FAA Support"; - break; - case INL_PHYCAP_2400MHZ: - default: - capabilities = "IEEE 802.11b/g"; /* Default */ - break; - } - strncpy(cwrq, capabilities, IFNAMSIZ); - return rvalue; -} - -static int -prism54_set_freq(struct net_device *ndev, struct iw_request_info *info, - struct iw_freq *fwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - int rvalue; - u32 c; - - if (fwrq->m < 1000) - /* we have a channel number */ - c = fwrq->m; - else - c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0; - - rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL; - - /* Call commit handler */ - return (rvalue ? rvalue : -EINPROGRESS); -} - -static int -prism54_get_freq(struct net_device *ndev, struct iw_request_info *info, - struct iw_freq *fwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - union oid_res_t r; - int rvalue; - - rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); - fwrq->i = r.u; - rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r); - fwrq->m = r.u; - fwrq->e = 3; - - return rvalue; -} - -static int -prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE; - - /* Let's see if the user passed a valid Linux Wireless mode */ - if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { - printk(KERN_DEBUG - "%s: %s() You passed a non-valid init_mode.\n", - priv->ndev->name, __func__); - return -EINVAL; - } - - down_write(&priv->mib_sem); - - if (prism54_mib_mode_helper(priv, *uwrq)) { - up_write(&priv->mib_sem); - return -EOPNOTSUPP; - } - - /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an - * extended one. - */ - if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN)) - mlmeautolevel = DOT11_MLME_INTERMEDIATE; - if (priv->wpa) - mlmeautolevel = DOT11_MLME_EXTENDED; - - mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); - - if (mgt_commit(priv)) { - up_write(&priv->mib_sem); - return -EIO; - } - priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) - ? priv->monitor_type : ARPHRD_ETHER; - up_write(&priv->mib_sem); - - return 0; -} - -/* Use mib cache */ -static int -prism54_get_mode(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - - BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode > - IW_MODE_MONITOR)); - *uwrq = priv->iw_mode; - - return 0; -} - -/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to - * emit data if (sensitivity > rssi - noise) (in dBm). - * prism54_set_sens does not seem to work. - */ - -static int -prism54_set_sens(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - u32 sens; - - /* by default the card sets this to 20. */ - sens = vwrq->disabled ? 20 : vwrq->value; - - return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); -} - -static int -prism54_get_sens(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - union oid_res_t r; - int rvalue; - - rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); - - vwrq->value = r.u; - vwrq->disabled = (vwrq->value == 0); - vwrq->fixed = 1; - - return rvalue; -} - -static int -prism54_get_range(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - struct iw_range *range = (struct iw_range *) extra; - islpci_private *priv = netdev_priv(ndev); - u8 *data; - int i, m, rvalue; - struct obj_frequencies *freq; - union oid_res_t r; - - memset(range, 0, sizeof (struct iw_range)); - dwrq->length = sizeof (struct iw_range); - - /* set the wireless extension version number */ - range->we_version_source = SUPPORTED_WIRELESS_EXT; - range->we_version_compiled = WIRELESS_EXT; - - /* Now the encoding capabilities */ - range->num_encoding_sizes = 3; - /* 64(40) bits WEP */ - range->encoding_size[0] = 5; - /* 128(104) bits WEP */ - range->encoding_size[1] = 13; - /* 256 bits for WPA-PSK */ - range->encoding_size[2] = 32; - /* 4 keys are allowed */ - range->max_encoding_tokens = 4; - - /* we don't know the quality range... */ - range->max_qual.level = 0; - range->max_qual.noise = 0; - range->max_qual.qual = 0; - /* these value describe an average quality. Needs more tweaking... */ - range->avg_qual.level = -80; /* -80 dBm */ - range->avg_qual.noise = 0; /* don't know what to put here */ - range->avg_qual.qual = 0; - - range->sensitivity = 200; - - /* retry limit capabilities */ - range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = IW_RETRY_LIFETIME; - - /* I don't know the range. Put stupid things here */ - range->min_retry = 1; - range->max_retry = 65535; - range->min_r_time = 1024; - range->max_r_time = 65535 * 1024; - - /* txpower is supported in dBm's */ - range->txpower_capa = IW_TXPOW_DBM; - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP; - - if (islpci_get_state(priv) < PRV_STATE_INIT) - return 0; - - /* Request the device for the supported frequencies - * not really relevant since some devices will report the 5 GHz band - * frequencies even if they don't support them. - */ - rvalue = - mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r); - freq = r.ptr; - - range->num_channels = freq->nr; - range->num_frequency = freq->nr; - - m = min(IW_MAX_FREQUENCIES, (int) freq->nr); - for (i = 0; i < m; i++) { - range->freq[i].m = freq->mhz[i]; - range->freq[i].e = 6; - range->freq[i].i = channel_of_freq(freq->mhz[i]); - } - kfree(freq); - - rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); - data = r.ptr; - - /* We got an array of char. It is NULL terminated. */ - i = 0; - while ((i < IW_MAX_BITRATES) && (*data != 0)) { - /* the result must be in bps. The card gives us 500Kbps */ - range->bitrate[i] = *data * 500000; - i++; - data++; - } - range->num_bitrates = i; - kfree(r.ptr); - - return rvalue; -} - -/* Set AP address*/ - -static int -prism54_set_wap(struct net_device *ndev, struct iw_request_info *info, - struct sockaddr *awrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - char bssid[6]; - int rvalue; - - if (awrq->sa_family != ARPHRD_ETHER) - return -EINVAL; - - /* prepare the structure for the set object */ - memcpy(&bssid[0], awrq->sa_data, ETH_ALEN); - - /* set the bssid -- does this make sense when in AP mode? */ - rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid); - - return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */ -} - -/* get AP address*/ - -static int -prism54_get_wap(struct net_device *ndev, struct iw_request_info *info, - struct sockaddr *awrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - union oid_res_t r; - int rvalue; - - rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); - memcpy(awrq->sa_data, r.ptr, ETH_ALEN); - awrq->sa_family = ARPHRD_ETHER; - kfree(r.ptr); - - return rvalue; -} - -static int -prism54_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - /* hehe the device does this automagicaly */ - return 0; -} - -/* a little helper that will translate our data into a card independent - * format that the Wireless Tools will understand. This was inspired by - * the "Aironet driver for 4500 and 4800 series cards" (GPL) - */ - -static char * -prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info, - char *current_ev, char *end_buf, struct obj_bss *bss, - char noise) -{ - struct iw_event iwe; /* Temporary buffer */ - short cap; - islpci_private *priv = netdev_priv(ndev); - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - - /* The first entry must be the MAC address */ - memcpy(iwe.u.ap_addr.sa_data, bss->address, ETH_ALEN); - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - iwe.cmd = SIOCGIWAP; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* The following entries will be displayed in the same order we give them */ - - /* The ESSID. */ - iwe.u.data.length = bss->ssid.length; - iwe.u.data.flags = 1; - iwe.cmd = SIOCGIWESSID; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->ssid.octets); - - /* Capabilities */ -#define CAP_ESS 0x01 -#define CAP_IBSS 0x02 -#define CAP_CRYPT 0x10 - - /* Mode */ - cap = bss->capinfo; - iwe.u.mode = 0; - if (cap & CAP_ESS) - iwe.u.mode = IW_MODE_MASTER; - else if (cap & CAP_IBSS) - iwe.u.mode = IW_MODE_ADHOC; - iwe.cmd = SIOCGIWMODE; - if (iwe.u.mode) - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - - /* Encryption capability */ - if (cap & CAP_CRYPT) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - iwe.cmd = SIOCGIWENCODE; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, NULL); - - /* Add frequency. (short) bss->channel is the frequency in MHz */ - iwe.u.freq.m = bss->channel; - iwe.u.freq.e = 6; - iwe.cmd = SIOCGIWFREQ; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - /* Add quality statistics */ - iwe.u.qual.level = bss->rssi; - iwe.u.qual.noise = noise; - /* do a simple SNR for quality */ - iwe.u.qual.qual = bss->rssi - noise; - iwe.cmd = IWEVQUAL; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add WPA/RSN Information Element, if any */ - wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie); - if (wpa_ie_len > 0) { - iwe.cmd = IWEVGENIE; - iwe.u.data.length = min_t(size_t, wpa_ie_len, MAX_WPA_IE_LEN); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, wpa_ie); - } - /* Do the bitrates */ - { - char *current_val = current_ev + iwe_stream_lcp_len(info); - int i; - int mask; - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - - /* Parse the bitmask */ - mask = 0x1; - for(i = 0; i < sizeof(scan_rate_list); i++) { - if(bss->rates & mask) { - iwe.u.bitrate.value = (scan_rate_list[i] * 500000); - current_val = iwe_stream_add_value( - info, current_ev, current_val, - end_buf, &iwe, IW_EV_PARAM_LEN); - } - mask <<= 1; - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - } - - return current_ev; -} - -static int -prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - int i, rvalue; - struct obj_bsslist *bsslist; - u32 noise = 0; - char *current_ev = extra; - union oid_res_t r; - - if (islpci_get_state(priv) < PRV_STATE_INIT) { - /* device is not ready, fail gently */ - dwrq->length = 0; - return 0; - } - - /* first get the noise value. We will use it to report the link quality */ - rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); - noise = r.u; - - /* Ask the device for a list of known bss. - * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64. - * The new API, using SIOCGIWSCAN, is only limited by the buffer size. - * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes. - * Starting with WE-17, the buffer can be as big as needed. - * But the device won't repport anything if you change the value - * of IWMAX_BSS=24. */ - - rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); - bsslist = r.ptr; - - /* ok now, scan the list and translate its info */ - for (i = 0; i < (int) bsslist->nr; i++) { - current_ev = prism54_translate_bss(ndev, info, current_ev, - extra + dwrq->length, - &(bsslist->bsslist[i]), - noise); - - /* Check if there is space for one more entry */ - if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - rvalue = -E2BIG; - break; - } - } - - kfree(bsslist); - dwrq->length = (current_ev - extra); - dwrq->flags = 0; /* todo */ - - return rvalue; -} - -static int -prism54_set_essid(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct obj_ssid essid; - - memset(essid.octets, 0, 33); - - /* Check if we were asked for `any' */ - if (dwrq->flags && dwrq->length) { - if (dwrq->length > 32) - return -E2BIG; - essid.length = dwrq->length; - memcpy(essid.octets, extra, dwrq->length); - } else - essid.length = 0; - - if (priv->iw_mode != IW_MODE_MONITOR) - return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid); - - /* If in monitor mode, just save to mib */ - mgt_set(priv, DOT11_OID_SSID, &essid); - return 0; - -} - -static int -prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct obj_ssid *essid; - union oid_res_t r; - int rvalue; - - rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r); - essid = r.ptr; - - if (essid->length) { - dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ - /* if it is too big, trunk it */ - dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length); - } else { - dwrq->flags = 0; - dwrq->length = 0; - } - essid->octets[dwrq->length] = '\0'; - memcpy(extra, essid->octets, dwrq->length); - kfree(essid); - - return rvalue; -} - -/* Provides no functionality, just completes the ioctl. In essence this is a - * just a cosmetic ioctl. - */ -static int -prism54_set_nick(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - - if (dwrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - down_write(&priv->mib_sem); - memset(priv->nickname, 0, sizeof (priv->nickname)); - memcpy(priv->nickname, extra, dwrq->length); - up_write(&priv->mib_sem); - - return 0; -} - -static int -prism54_get_nick(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - - dwrq->length = 0; - - down_read(&priv->mib_sem); - dwrq->length = strlen(priv->nickname); - memcpy(extra, priv->nickname, dwrq->length); - up_read(&priv->mib_sem); - - return 0; -} - -/* Set the allowed Bitrates */ - -static int -prism54_set_rate(struct net_device *ndev, - struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - - islpci_private *priv = netdev_priv(ndev); - u32 rate, profile; - char *data; - int ret, i; - union oid_res_t r; - - if (vwrq->value == -1) { - /* auto mode. No limit. */ - profile = 1; - return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); - } - - ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); - if (ret) { - kfree(r.ptr); - return ret; - } - - rate = (u32) (vwrq->value / 500000); - data = r.ptr; - i = 0; - - while (data[i]) { - if (rate && (data[i] == rate)) { - break; - } - if (vwrq->value == i) { - break; - } - data[i] |= 0x80; - i++; - } - - if (!data[i]) { - kfree(r.ptr); - return -EINVAL; - } - - data[i] |= 0x80; - data[i + 1] = 0; - - /* Now, check if we want a fixed or auto value */ - if (vwrq->fixed) { - data[0] = data[i]; - data[1] = 0; - } - -/* - i = 0; - printk("prism54 rate: "); - while(data[i]) { - printk("%u ", data[i]); - i++; - } - printk("0\n"); -*/ - profile = -1; - ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); - ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data); - ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data); - - kfree(r.ptr); - - return ret; -} - -/* Get the current bit rate */ -static int -prism54_get_rate(struct net_device *ndev, - struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - int rvalue; - char *data; - union oid_res_t r; - - /* Get the current bit rate */ - if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r))) - return rvalue; - vwrq->value = r.u * 500000; - - /* request the device for the enabled rates */ - rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r); - if (rvalue) { - kfree(r.ptr); - return rvalue; - } - data = r.ptr; - vwrq->fixed = (data[0] != 0) && (data[1] == 0); - kfree(r.ptr); - - return 0; -} - -static int -prism54_set_rts(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - - return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value); -} - -static int -prism54_get_rts(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - union oid_res_t r; - int rvalue; - - /* get the rts threshold */ - rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r); - vwrq->value = r.u; - - return rvalue; -} - -static int -prism54_set_frag(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - - return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value); -} - -static int -prism54_get_frag(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - union oid_res_t r; - int rvalue; - - rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r); - vwrq->value = r.u; - - return rvalue; -} - -/* Here we have (min,max) = max retries for (small frames, big frames). Where - * big frame <=> bigger than the rts threshold - * small frame <=> smaller than the rts threshold - * This is not really the behavior expected by the wireless tool but it seems - * to be a common behavior in other drivers. - */ - -static int -prism54_set_retry(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - u32 slimit = 0, llimit = 0; /* short and long limit */ - u32 lifetime = 0; - int rvalue = 0; - - if (vwrq->disabled) - /* we cannot disable this feature */ - return -EINVAL; - - if (vwrq->flags & IW_RETRY_LIMIT) { - if (vwrq->flags & IW_RETRY_SHORT) - slimit = vwrq->value; - else if (vwrq->flags & IW_RETRY_LONG) - llimit = vwrq->value; - else { - /* we are asked to set both */ - slimit = vwrq->value; - llimit = vwrq->value; - } - } - if (vwrq->flags & IW_RETRY_LIFETIME) - /* Wireless tools use us unit while the device uses 1024 us unit */ - lifetime = vwrq->value / 1024; - - /* now set what is requested */ - if (slimit) - rvalue = - mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit); - if (llimit) - rvalue |= - mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit); - if (lifetime) - rvalue |= - mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0, - &lifetime); - return rvalue; -} - -static int -prism54_get_retry(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - union oid_res_t r; - int rvalue = 0; - vwrq->disabled = 0; /* It cannot be disabled */ - - if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - /* we are asked for the life time */ - rvalue = - mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); - vwrq->value = r.u * 1024; - vwrq->flags = IW_RETRY_LIFETIME; - } else if ((vwrq->flags & IW_RETRY_LONG)) { - /* we are asked for the long retry limit */ - rvalue |= - mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); - vwrq->value = r.u; - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - } else { - /* default. get the short retry limit */ - rvalue |= - mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); - vwrq->value = r.u; - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; - } - - return rvalue; -} - -static int -prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - int rvalue = 0, force = 0; - int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; - union oid_res_t r; - - /* with the new API, it's impossible to get a NULL pointer. - * New version of iwconfig set the IW_ENCODE_NOKEY flag - * when no key is given, but older versions don't. */ - - if (dwrq->length > 0) { - /* we have a key to set */ - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - int current_index; - struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; - - /* get the current key index */ - rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); - current_index = r.u; - /* Verify that the key is not marked as invalid */ - if (!(dwrq->flags & IW_ENCODE_NOKEY)) { - if (dwrq->length > KEY_SIZE_TKIP) { - /* User-provided key data too big */ - return -EINVAL; - } - if (dwrq->length > KEY_SIZE_WEP104) { - /* WPA-PSK TKIP */ - key.type = DOT11_PRIV_TKIP; - key.length = KEY_SIZE_TKIP; - } else if (dwrq->length > KEY_SIZE_WEP40) { - /* WEP 104/128 */ - key.length = KEY_SIZE_WEP104; - } else { - /* WEP 40/64 */ - key.length = KEY_SIZE_WEP40; - } - memset(key.key, 0, sizeof (key.key)); - memcpy(key.key, extra, dwrq->length); - - if ((index < 0) || (index > 3)) - /* no index provided use the current one */ - index = current_index; - - /* now send the key to the card */ - rvalue |= - mgt_set_request(priv, DOT11_OID_DEFKEYX, index, - &key); - } - /* - * If a valid key is set, encryption should be enabled - * (user may turn it off later). - * This is also how "iwconfig ethX key on" works - */ - if ((index == current_index) && (key.length > 0)) - force = 1; - } else { - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if ((index >= 0) && (index <= 3)) { - /* we want to set the key index */ - rvalue |= - mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, - &index); - } else { - if (!(dwrq->flags & IW_ENCODE_MODE)) { - /* we cannot do anything. Complain. */ - return -EINVAL; - } - } - } - /* now read the flags */ - if (dwrq->flags & IW_ENCODE_DISABLED) { - /* Encoding disabled, - * authen = DOT11_AUTH_OS; - * invoke = 0; - * exunencrypt = 0; */ - } - if (dwrq->flags & IW_ENCODE_OPEN) - /* Encode but accept non-encoded packets. No auth */ - invoke = 1; - if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) { - /* Refuse non-encoded packets. Auth */ - authen = DOT11_AUTH_BOTH; - invoke = 1; - exunencrypt = 1; - } - /* do the change if requested */ - if ((dwrq->flags & IW_ENCODE_MODE) || force) { - rvalue |= - mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); - rvalue |= - mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); - rvalue |= - mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, - &exunencrypt); - } - return rvalue; -} - -static int -prism54_get_encode(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct obj_key *key; - u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - u32 authen = 0, invoke = 0, exunencrypt = 0; - int rvalue; - union oid_res_t r; - - /* first get the flags */ - rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); - authen = r.u; - rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); - invoke = r.u; - rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); - exunencrypt = r.u; - - if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt) - dwrq->flags = IW_ENCODE_RESTRICTED; - else if ((authen == DOT11_AUTH_OS) && !exunencrypt) { - if (invoke) - dwrq->flags = IW_ENCODE_OPEN; - else - dwrq->flags = IW_ENCODE_DISABLED; - } else - /* The card should not work in this state */ - dwrq->flags = 0; - - /* get the current device key index */ - rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); - devindex = r.u; - /* Now get the key, return it */ - if (index == -1 || index > 3) - /* no index provided, use the current one */ - index = devindex; - rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r); - key = r.ptr; - dwrq->length = key->length; - memcpy(extra, key->key, dwrq->length); - kfree(key); - /* return the used key index */ - dwrq->flags |= devindex + 1; - - return rvalue; -} - -static int -prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - union oid_res_t r; - int rvalue; - - rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r); - /* intersil firmware operates in 0.25 dBm (1/4 dBm) */ - vwrq->value = (s32) r.u / 4; - vwrq->fixed = 1; - /* radio is not turned of - * btw: how is possible to turn off only the radio - */ - vwrq->disabled = 0; - - return rvalue; -} - -static int -prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - s32 u = vwrq->value; - - /* intersil firmware operates in 0.25 dBm (1/4) */ - u *= 4; - if (vwrq->disabled) { - /* don't know how to disable radio */ - printk(KERN_DEBUG - "%s: %s() disabling radio is not yet supported.\n", - priv->ndev->name, __func__); - return -ENOTSUPP; - } else if (vwrq->fixed) - /* currently only fixed value is supported */ - return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u); - else { - printk(KERN_DEBUG - "%s: %s() auto power will be implemented later.\n", - priv->ndev->name, __func__); - return -ENOTSUPP; - } -} - -static int prism54_set_genie(struct net_device *ndev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - int alen, ret = 0; - struct obj_attachment *attach; - - if (data->length > MAX_WPA_IE_LEN || - (data->length && extra == NULL)) - return -EINVAL; - - memcpy(priv->wpa_ie, extra, data->length); - priv->wpa_ie_len = data->length; - - alen = sizeof(*attach) + priv->wpa_ie_len; - attach = kzalloc(alen, GFP_KERNEL); - if (attach == NULL) - return -ENOMEM; - -#define WLAN_FC_TYPE_MGMT 0 -#define WLAN_FC_STYPE_ASSOC_REQ 0 -#define WLAN_FC_STYPE_REASSOC_REQ 2 - - /* Note: endianness is covered by mgt_set_varlen */ - attach->type = (WLAN_FC_TYPE_MGMT << 2) | - (WLAN_FC_STYPE_ASSOC_REQ << 4); - attach->id = -1; - attach->size = priv->wpa_ie_len; - memcpy(attach->data, extra, priv->wpa_ie_len); - - ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, - priv->wpa_ie_len); - if (ret == 0) { - attach->type = (WLAN_FC_TYPE_MGMT << 2) | - (WLAN_FC_STYPE_REASSOC_REQ << 4); - - ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, - priv->wpa_ie_len); - if (ret == 0) - printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", - ndev->name); - } - - kfree(attach); - return ret; -} - - -static int prism54_get_genie(struct net_device *ndev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - int len = priv->wpa_ie_len; - - if (len <= 0) { - data->length = 0; - return 0; - } - - if (data->length < len) - return -E2BIG; - - data->length = len; - memcpy(extra, priv->wpa_ie, len); - - return 0; -} - -static int prism54_set_auth(struct net_device *ndev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct iw_param *param = &wrqu->param; - u32 mlmelevel = 0, authen = 0, dot1x = 0; - u32 exunencrypt = 0, privinvoked = 0, wpa = 0; - u32 old_wpa; - int ret = 0; - union oid_res_t r; - - if (islpci_get_state(priv) < PRV_STATE_INIT) - return 0; - - /* first get the flags */ - down_write(&priv->mib_sem); - wpa = old_wpa = priv->wpa; - up_write(&priv->mib_sem); - ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); - authen = r.u; - ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); - privinvoked = r.u; - ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); - exunencrypt = r.u; - ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); - dot1x = r.u; - ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r); - mlmelevel = r.u; - - if (ret < 0) - goto out; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - break; - - case IW_AUTH_WPA_ENABLED: - /* Do the same thing as IW_AUTH_WPA_VERSION */ - if (param->value) { - wpa = 1; - privinvoked = 1; /* For privacy invoked */ - exunencrypt = 1; /* Filter out all unencrypted frames */ - dot1x = 0x01; /* To enable eap filter */ - mlmelevel = DOT11_MLME_EXTENDED; - authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ - } else { - wpa = 0; - privinvoked = 0; - exunencrypt = 0; /* Do not filter un-encrypted data */ - dot1x = 0; - mlmelevel = DOT11_MLME_AUTO; - } - break; - - case IW_AUTH_WPA_VERSION: - if (param->value & IW_AUTH_WPA_VERSION_DISABLED) { - wpa = 0; - privinvoked = 0; - exunencrypt = 0; /* Do not filter un-encrypted data */ - dot1x = 0; - mlmelevel = DOT11_MLME_AUTO; - } else { - if (param->value & IW_AUTH_WPA_VERSION_WPA) - wpa = 1; - else if (param->value & IW_AUTH_WPA_VERSION_WPA2) - wpa = 2; - privinvoked = 1; /* For privacy invoked */ - exunencrypt = 1; /* Filter out all unencrypted frames */ - dot1x = 0x01; /* To enable eap filter */ - mlmelevel = DOT11_MLME_EXTENDED; - authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ - } - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - /* dot1x should be the opposite of RX_UNENCRYPTED_EAPOL; - * turn off dot1x when allowing receipt of unencrypted EAPOL - * frames, turn on dot1x when receipt should be disallowed - */ - dot1x = param->value ? 0 : 0x01; - break; - - case IW_AUTH_PRIVACY_INVOKED: - privinvoked = param->value ? 1 : 0; - break; - - case IW_AUTH_DROP_UNENCRYPTED: - exunencrypt = param->value ? 1 : 0; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) { - /* Only WEP uses _SK and _BOTH */ - if (wpa > 0) { - ret = -EINVAL; - goto out; - } - authen = DOT11_AUTH_SK; - } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { - authen = DOT11_AUTH_OS; - } else { - ret = -EINVAL; - goto out; - } - break; - - default: - return -EOPNOTSUPP; - } - - /* Set all the values */ - down_write(&priv->mib_sem); - priv->wpa = wpa; - up_write(&priv->mib_sem); - mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); - mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked); - mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt); - mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); - mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel); - -out: - return ret; -} - -static int prism54_get_auth(struct net_device *ndev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct iw_param *param = &wrqu->param; - u32 wpa = 0; - int ret = 0; - union oid_res_t r; - - if (islpci_get_state(priv) < PRV_STATE_INIT) - return 0; - - /* first get the flags */ - down_write(&priv->mib_sem); - wpa = priv->wpa; - up_write(&priv->mib_sem); - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * wpa_supplicant will control these internally - */ - ret = -EOPNOTSUPP; - break; - - case IW_AUTH_WPA_VERSION: - switch (wpa) { - case 1: - param->value = IW_AUTH_WPA_VERSION_WPA; - break; - case 2: - param->value = IW_AUTH_WPA_VERSION_WPA2; - break; - case 0: - default: - param->value = IW_AUTH_WPA_VERSION_DISABLED; - break; - } - break; - - case IW_AUTH_DROP_UNENCRYPTED: - ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); - if (ret >= 0) - param->value = r.u > 0 ? 1 : 0; - break; - - case IW_AUTH_80211_AUTH_ALG: - ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); - if (ret >= 0) { - switch (r.u) { - case DOT11_AUTH_OS: - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - case DOT11_AUTH_BOTH: - case DOT11_AUTH_SK: - param->value = IW_AUTH_ALG_SHARED_KEY; - break; - case DOT11_AUTH_NONE: - default: - param->value = 0; - break; - } - } - break; - - case IW_AUTH_WPA_ENABLED: - param->value = wpa > 0 ? 1 : 0; - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); - if (ret >= 0) - param->value = r.u > 0 ? 1 : 0; - break; - - case IW_AUTH_PRIVACY_INVOKED: - ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); - if (ret >= 0) - param->value = r.u > 0 ? 1 : 0; - break; - - default: - return -EOPNOTSUPP; - } - return ret; -} - -static int prism54_set_encodeext(struct net_device *ndev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, alg = ext->alg, set_key = 1; - union oid_res_t r; - int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; - int ret = 0; - - if (islpci_get_state(priv) < PRV_STATE_INIT) - return 0; - - /* Determine and validate the key index */ - idx = (encoding->flags & IW_ENCODE_INDEX) - 1; - if (idx) { - if (idx < 0 || idx > 3) - return -EINVAL; - } else { - ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); - if (ret < 0) - goto out; - idx = r.u; - } - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - /* Only set transmit key index here, actual - * key is set below if needed. - */ - ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx); - set_key = ext->key_len > 0 ? 1 : 0; - } - - if (set_key) { - struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; - switch (alg) { - case IW_ENCODE_ALG_NONE: - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len > KEY_SIZE_WEP104) { - ret = -EINVAL; - goto out; - } - if (ext->key_len > KEY_SIZE_WEP40) - key.length = KEY_SIZE_WEP104; - else - key.length = KEY_SIZE_WEP40; - break; - case IW_ENCODE_ALG_TKIP: - if (ext->key_len > KEY_SIZE_TKIP) { - ret = -EINVAL; - goto out; - } - key.type = DOT11_PRIV_TKIP; - key.length = KEY_SIZE_TKIP; - break; - default: - return -EINVAL; - } - - if (key.length) { - memset(key.key, 0, sizeof(key.key)); - memcpy(key.key, ext->key, ext->key_len); - ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx, - &key); - if (ret < 0) - goto out; - } - } - - /* Read the flags */ - if (encoding->flags & IW_ENCODE_DISABLED) { - /* Encoding disabled, - * authen = DOT11_AUTH_OS; - * invoke = 0; - * exunencrypt = 0; */ - } - if (encoding->flags & IW_ENCODE_OPEN) { - /* Encode but accept non-encoded packets. No auth */ - invoke = 1; - } - if (encoding->flags & IW_ENCODE_RESTRICTED) { - /* Refuse non-encoded packets. Auth */ - authen = DOT11_AUTH_BOTH; - invoke = 1; - exunencrypt = 1; - } - - /* do the change if requested */ - if (encoding->flags & IW_ENCODE_MODE) { - ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, - &authen); - ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, - &invoke); - ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, - &exunencrypt); - } - -out: - return ret; -} - - -static int prism54_get_encodeext(struct net_device *ndev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - union oid_res_t r; - int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0; - int ret = 0; - - if (islpci_get_state(priv) < PRV_STATE_INIT) - return 0; - - /* first get the flags */ - ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); - authen = r.u; - ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); - invoke = r.u; - ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); - exunencrypt = r.u; - if (ret < 0) - goto out; - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = (encoding->flags & IW_ENCODE_INDEX) - 1; - if (idx) { - if (idx < 0 || idx > 3) - return -EINVAL; - } else { - ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); - if (ret < 0) - goto out; - idx = r.u; - } - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - switch (authen) { - case DOT11_AUTH_BOTH: - case DOT11_AUTH_SK: - wrqu->encoding.flags |= IW_ENCODE_RESTRICTED; - fallthrough; - case DOT11_AUTH_OS: - default: - wrqu->encoding.flags |= IW_ENCODE_OPEN; - break; - } - - down_write(&priv->mib_sem); - wpa = priv->wpa; - up_write(&priv->mib_sem); - - if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) { - /* No encryption */ - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - wrqu->encoding.flags |= IW_ENCODE_DISABLED; - } else { - struct obj_key *key; - - ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r); - if (ret < 0) - goto out; - key = r.ptr; - if (max_key_len < key->length) { - ret = -E2BIG; - goto out; - } - memcpy(ext->key, key->key, key->length); - ext->key_len = key->length; - - switch (key->type) { - case DOT11_PRIV_TKIP: - ext->alg = IW_ENCODE_ALG_TKIP; - break; - default: - case DOT11_PRIV_WEP: - ext->alg = IW_ENCODE_ALG_WEP; - break; - } - wrqu->encoding.flags |= IW_ENCODE_ENABLED; - } - -out: - return ret; -} - - -static int -prism54_reset(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_reset(netdev_priv(ndev), 0); - - return 0; -} - -static int -prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - union oid_res_t r; - int rvalue; - enum oid_num_t n = dwrq->flags; - - rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r); - dwrq->length = mgt_response_to_str(n, &r, extra); - if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32) - kfree(r.ptr); - return rvalue; -} - -static int -prism54_set_u32(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - u32 oid = uwrq[0], u = uwrq[1]; - - return mgt_set_request(netdev_priv(ndev), oid, 0, &u); -} - -static int -prism54_set_raw(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - u32 oid = dwrq->flags; - - return mgt_set_request(netdev_priv(ndev), oid, 0, extra); -} - -void -prism54_acl_init(struct islpci_acl *acl) -{ - mutex_init(&acl->lock); - INIT_LIST_HEAD(&acl->mac_list); - acl->size = 0; - acl->policy = MAC_POLICY_OPEN; -} - -static void -prism54_clear_mac(struct islpci_acl *acl) -{ - struct list_head *ptr, *next; - struct mac_entry *entry; - - mutex_lock(&acl->lock); - - if (acl->size == 0) { - mutex_unlock(&acl->lock); - return; - } - - for (ptr = acl->mac_list.next, next = ptr->next; - ptr != &acl->mac_list; ptr = next, next = ptr->next) { - entry = list_entry(ptr, struct mac_entry, _list); - list_del(ptr); - kfree(entry); - } - acl->size = 0; - mutex_unlock(&acl->lock); -} - -void -prism54_acl_clean(struct islpci_acl *acl) -{ - prism54_clear_mac(acl); -} - -static int -prism54_add_mac(struct net_device *ndev, struct iw_request_info *info, - struct sockaddr *awrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct islpci_acl *acl = &priv->acl; - struct mac_entry *entry; - struct sockaddr *addr = (struct sockaddr *) extra; - - if (addr->sa_family != ARPHRD_ETHER) - return -EOPNOTSUPP; - - entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL); - if (entry == NULL) - return -ENOMEM; - - memcpy(entry->addr, addr->sa_data, ETH_ALEN); - - if (mutex_lock_interruptible(&acl->lock)) { - kfree(entry); - return -ERESTARTSYS; - } - list_add_tail(&entry->_list, &acl->mac_list); - acl->size++; - mutex_unlock(&acl->lock); - - return 0; -} - -static int -prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, - struct sockaddr *awrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct islpci_acl *acl = &priv->acl; - struct mac_entry *entry; - struct sockaddr *addr = (struct sockaddr *) extra; - - if (addr->sa_family != ARPHRD_ETHER) - return -EOPNOTSUPP; - - if (mutex_lock_interruptible(&acl->lock)) - return -ERESTARTSYS; - list_for_each_entry(entry, &acl->mac_list, _list) { - if (ether_addr_equal(entry->addr, addr->sa_data)) { - list_del(&entry->_list); - acl->size--; - kfree(entry); - mutex_unlock(&acl->lock); - return 0; - } - } - mutex_unlock(&acl->lock); - return -EINVAL; -} - -static int -prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct islpci_acl *acl = &priv->acl; - struct mac_entry *entry; - struct sockaddr *dst = (struct sockaddr *) extra; - - dwrq->length = 0; - - if (mutex_lock_interruptible(&acl->lock)) - return -ERESTARTSYS; - - list_for_each_entry(entry, &acl->mac_list, _list) { - memcpy(dst->sa_data, entry->addr, ETH_ALEN); - dst->sa_family = ARPHRD_ETHER; - dwrq->length++; - dst++; - } - mutex_unlock(&acl->lock); - return 0; -} - -/* Setting policy also clears the MAC acl, even if we don't change the default - * policy - */ - -static int -prism54_set_policy(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct islpci_acl *acl = &priv->acl; - u32 mlmeautolevel; - - prism54_clear_mac(acl); - - if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT)) - return -EINVAL; - - down_write(&priv->mib_sem); - - acl->policy = *uwrq; - - /* the ACL code needs an intermediate mlmeautolevel */ - if ((priv->iw_mode == IW_MODE_MASTER) && - (acl->policy != MAC_POLICY_OPEN)) - mlmeautolevel = DOT11_MLME_INTERMEDIATE; - else - mlmeautolevel = CARD_DEFAULT_MLME_MODE; - if (priv->wpa) - mlmeautolevel = DOT11_MLME_EXTENDED; - mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); - /* restart the card with our new policy */ - if (mgt_commit(priv)) { - up_write(&priv->mib_sem); - return -EIO; - } - up_write(&priv->mib_sem); - - return 0; -} - -static int -prism54_get_policy(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct islpci_acl *acl = &priv->acl; - - *uwrq = acl->policy; - - return 0; -} - -/* Return 1 only if client should be accepted. */ - -static int -prism54_mac_accept(struct islpci_acl *acl, char *mac) -{ - struct mac_entry *entry; - int res = 0; - - if (mutex_lock_interruptible(&acl->lock)) - return -ERESTARTSYS; - - if (acl->policy == MAC_POLICY_OPEN) { - mutex_unlock(&acl->lock); - return 1; - } - - list_for_each_entry(entry, &acl->mac_list, _list) { - if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { - res = 1; - break; - } - } - res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; - mutex_unlock(&acl->lock); - - return res; -} - -static int -prism54_kick_all(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - struct obj_mlme *mlme; - int rvalue; - - mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); - if (mlme == NULL) - return -ENOMEM; - - /* Tell the card to kick every client */ - mlme->id = 0; - rvalue = - mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); - kfree(mlme); - - return rvalue; -} - -static int -prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info, - struct sockaddr *awrq, char *extra) -{ - struct obj_mlme *mlme; - struct sockaddr *addr = (struct sockaddr *) extra; - int rvalue; - - if (addr->sa_family != ARPHRD_ETHER) - return -EOPNOTSUPP; - - mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); - if (mlme == NULL) - return -ENOMEM; - - /* Tell the card to only kick the corresponding bastard */ - memcpy(mlme->address, addr->sa_data, ETH_ALEN); - mlme->id = -1; - rvalue = - mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); - - kfree(mlme); - - return rvalue; -} - -/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */ - -static void -format_event(islpci_private *priv, char *dest, const char *str, - const struct obj_mlme *mlme, u16 *length, int error) -{ - int n = snprintf(dest, IW_CUSTOM_MAX, - "%s %s %pM %s (%2.2X)", - str, - ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), - mlme->address, - (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") - : ""), mlme->code); - WARN_ON(n >= IW_CUSTOM_MAX); - *length = n; -} - -static void -send_formatted_event(islpci_private *priv, const char *str, - const struct obj_mlme *mlme, int error) -{ - union iwreq_data wrqu; - char *memptr; - - memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); - if (!memptr) - return; - wrqu.data.pointer = memptr; - wrqu.data.length = 0; - format_event(priv, memptr, str, mlme, &wrqu.data.length, - error); - wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr); - kfree(memptr); -} - -static void -send_simple_event(islpci_private *priv, const char *str) -{ - union iwreq_data wrqu; - char *memptr; - int n = strlen(str); - - memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); - if (!memptr) - return; - BUG_ON(n >= IW_CUSTOM_MAX); - wrqu.data.pointer = memptr; - wrqu.data.length = n; - strcpy(memptr, str); - wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr); - kfree(memptr); -} - -static void -link_changed(struct net_device *ndev, u32 bitrate) -{ - islpci_private *priv = netdev_priv(ndev); - - if (bitrate) { - netif_carrier_on(ndev); - if (priv->iw_mode == IW_MODE_INFRA) { - union iwreq_data uwrq; - prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, - NULL); - wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL); - } else - send_simple_event(netdev_priv(ndev), - "Link established"); - } else { - netif_carrier_off(ndev); - send_simple_event(netdev_priv(ndev), "Link lost"); - } -} - -/* Beacon/ProbeResp payload header */ -struct ieee80211_beacon_phdr { - u8 timestamp[8]; - u16 beacon_int; - u16 capab_info; -} __packed; - -#define WLAN_EID_GENERIC 0xdd -static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; - -static void -prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, - u8 *wpa_ie, size_t wpa_ie_len) -{ - struct list_head *ptr; - struct islpci_bss_wpa_ie *bss = NULL; - - if (wpa_ie_len > MAX_WPA_IE_LEN) - wpa_ie_len = MAX_WPA_IE_LEN; - - mutex_lock(&priv->wpa_lock); - - /* try to use existing entry */ - list_for_each(ptr, &priv->bss_wpa_list) { - bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); - if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { - list_move(&bss->list, &priv->bss_wpa_list); - break; - } - bss = NULL; - } - - if (bss == NULL) { - /* add a new BSS entry; if max number of entries is already - * reached, replace the least recently updated */ - if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) { - bss = list_entry(priv->bss_wpa_list.prev, - struct islpci_bss_wpa_ie, list); - list_del(&bss->list); - } else { - bss = kzalloc(sizeof (*bss), GFP_ATOMIC); - if (bss != NULL) - priv->num_bss_wpa++; - } - if (bss != NULL) { - memcpy(bss->bssid, bssid, ETH_ALEN); - list_add(&bss->list, &priv->bss_wpa_list); - } - } - - if (bss != NULL) { - memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len); - bss->wpa_ie_len = wpa_ie_len; - bss->last_update = jiffies; - } else { - printk(KERN_DEBUG "Failed to add BSS WPA entry for " - "%pM\n", bssid); - } - - /* expire old entries from WPA list */ - while (priv->num_bss_wpa > 0) { - bss = list_entry(priv->bss_wpa_list.prev, - struct islpci_bss_wpa_ie, list); - if (!time_after(jiffies, bss->last_update + 60 * HZ)) - break; - - list_del(&bss->list); - priv->num_bss_wpa--; - kfree(bss); - } - - mutex_unlock(&priv->wpa_lock); -} - -static size_t -prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) -{ - struct list_head *ptr; - struct islpci_bss_wpa_ie *bss = NULL; - size_t len = 0; - - mutex_lock(&priv->wpa_lock); - - list_for_each(ptr, &priv->bss_wpa_list) { - bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); - if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) - break; - bss = NULL; - } - if (bss) { - len = bss->wpa_ie_len; - memcpy(wpa_ie, bss->wpa_ie, len); - } - mutex_unlock(&priv->wpa_lock); - - return len; -} - -void -prism54_wpa_bss_ie_init(islpci_private *priv) -{ - INIT_LIST_HEAD(&priv->bss_wpa_list); - mutex_init(&priv->wpa_lock); -} - -void -prism54_wpa_bss_ie_clean(islpci_private *priv) -{ - struct islpci_bss_wpa_ie *bss, *n; - - list_for_each_entry_safe(bss, n, &priv->bss_wpa_list, list) { - kfree(bss); - } -} - -static void -prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, - u8 *payload, size_t len) -{ - struct ieee80211_beacon_phdr *hdr; - u8 *pos, *end; - - if (!priv->wpa) - return; - - hdr = (struct ieee80211_beacon_phdr *) payload; - pos = (u8 *) (hdr + 1); - end = payload + len; - while (pos < end) { - if (pos + 2 + pos[1] > end) { - printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " - "for %pM\n", addr); - return; - } - if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && - memcmp(pos + 2, wpa_oid, 4) == 0) { - prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2); - return; - } - pos += 2 + pos[1]; - } -} - -static void -handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid) -{ - if (((mlme->state == DOT11_STATE_AUTHING) || - (mlme->state == DOT11_STATE_ASSOCING)) - && mgt_mlme_answer(priv)) { - /* Someone is requesting auth and we must respond. Just send back - * the trap with error code set accordingly. - */ - mlme->code = prism54_mac_accept(&priv->acl, - mlme->address) ? 0 : 1; - mgt_set_request(priv, oid, 0, mlme); - } -} - -static int -prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, - char *data) -{ - struct obj_mlme *mlme = (struct obj_mlme *) data; - struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data; - struct obj_mlmeex *confirm; - u8 wpa_ie[MAX_WPA_IE_LEN]; - int wpa_ie_len; - size_t len = 0; /* u16, better? */ - u8 *payload = NULL, *pos = NULL; - int ret; - - /* I think all trapable objects are listed here. - * Some oids have a EX version. The difference is that they are emitted - * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL) - * with more info. - * The few events already defined by the wireless tools are not really - * suited. We use the more flexible custom event facility. - */ - - if (oid >= DOT11_OID_BEACON) { - len = mlmeex->size; - payload = pos = mlmeex->data; - } - - /* I fear prism54_process_bss_data won't work with big endian data */ - if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE)) - prism54_process_bss_data(priv, oid, mlmeex->address, - payload, len); - - mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme); - - switch (oid) { - - case GEN_OID_LINKSTATE: - link_changed(priv->ndev, (u32) *data); - break; - - case DOT11_OID_MICFAILURE: - send_simple_event(priv, "Mic failure"); - break; - - case DOT11_OID_DEAUTHENTICATE: - send_formatted_event(priv, "DeAuthenticate request", mlme, 0); - break; - - case DOT11_OID_AUTHENTICATE: - handle_request(priv, mlme, oid); - send_formatted_event(priv, "Authenticate request", mlme, 1); - break; - - case DOT11_OID_DISASSOCIATE: - send_formatted_event(priv, "Disassociate request", mlme, 0); - break; - - case DOT11_OID_ASSOCIATE: - handle_request(priv, mlme, oid); - send_formatted_event(priv, "Associate request", mlme, 1); - break; - - case DOT11_OID_REASSOCIATE: - handle_request(priv, mlme, oid); - send_formatted_event(priv, "ReAssociate request", mlme, 1); - break; - - case DOT11_OID_BEACON: - send_formatted_event(priv, - "Received a beacon from an unknown AP", - mlme, 0); - break; - - case DOT11_OID_PROBE: - /* we received a probe from a client. */ - send_formatted_event(priv, "Received a probe from client", mlme, - 0); - break; - - /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this - * is backward compatible layout-wise with "struct obj_mlme". - */ - - case DOT11_OID_DEAUTHENTICATEEX: - send_formatted_event(priv, "DeAuthenticate request", mlme, 0); - break; - - case DOT11_OID_AUTHENTICATEEX: - handle_request(priv, mlme, oid); - send_formatted_event(priv, "Authenticate request (ex)", mlme, 1); - - if (priv->iw_mode != IW_MODE_MASTER - && mlmeex->state != DOT11_STATE_AUTHING) - break; - - confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC); - - if (!confirm) - break; - - memcpy(&confirm->address, mlmeex->address, ETH_ALEN); - printk(KERN_DEBUG "Authenticate from: address:\t%pM\n", - mlmeex->address); - confirm->id = -1; /* or mlmeex->id ? */ - confirm->state = 0; /* not used */ - confirm->code = 0; - confirm->size = 6; - confirm->data[0] = 0x00; - confirm->data[1] = 0x00; - confirm->data[2] = 0x02; - confirm->data[3] = 0x00; - confirm->data[4] = 0x00; - confirm->data[5] = 0x00; - - ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6); - - kfree(confirm); - if (ret) - return ret; - break; - - case DOT11_OID_DISASSOCIATEEX: - send_formatted_event(priv, "Disassociate request (ex)", mlme, 0); - break; - - case DOT11_OID_ASSOCIATEEX: - handle_request(priv, mlme, oid); - send_formatted_event(priv, "Associate request (ex)", mlme, 1); - - if (priv->iw_mode != IW_MODE_MASTER - && mlmeex->state != DOT11_STATE_ASSOCING) - break; - - confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); - - if (!confirm) - break; - - memcpy(&confirm->address, mlmeex->address, ETH_ALEN); - - confirm->id = ((struct obj_mlmeex *)mlme)->id; - confirm->state = 0; /* not used */ - confirm->code = 0; - - wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); - - if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", - mlmeex->address); - kfree(confirm); - break; - } - - confirm->size = wpa_ie_len; - memcpy(&confirm->data, wpa_ie, wpa_ie_len); - - mgt_set_varlen(priv, oid, confirm, wpa_ie_len); - - kfree(confirm); - - break; - - case DOT11_OID_REASSOCIATEEX: - handle_request(priv, mlme, oid); - send_formatted_event(priv, "Reassociate request (ex)", mlme, 1); - - if (priv->iw_mode != IW_MODE_MASTER - && mlmeex->state != DOT11_STATE_ASSOCING) - break; - - confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); - - if (!confirm) - break; - - memcpy(&confirm->address, mlmeex->address, ETH_ALEN); - - confirm->id = mlmeex->id; - confirm->state = 0; /* not used */ - confirm->code = 0; - - wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); - - if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", - mlmeex->address); - kfree(confirm); - break; - } - - confirm->size = wpa_ie_len; - memcpy(&confirm->data, wpa_ie, wpa_ie_len); - - mgt_set_varlen(priv, oid, confirm, wpa_ie_len); - - kfree(confirm); - - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * Process a device trap. This is called via schedule_work(), outside of - * interrupt context, no locks held. - */ -void -prism54_process_trap(struct work_struct *work) -{ - struct islpci_mgmtframe *frame = - container_of(work, struct islpci_mgmtframe, ws); - struct net_device *ndev = frame->ndev; - enum oid_num_t n = mgt_oidtonum(frame->header->oid); - - if (n != OID_NUM_LAST) - prism54_process_trap_helper(netdev_priv(ndev), n, frame->data); - islpci_mgt_release(frame); -} - -int -prism54_set_mac_address(struct net_device *ndev, void *addr) -{ - islpci_private *priv = netdev_priv(ndev); - int ret; - - if (ndev->addr_len != 6) - return -EINVAL; - ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0, - &((struct sockaddr *) addr)->sa_data); - if (!ret) - memcpy(priv->ndev->dev_addr, - &((struct sockaddr *) addr)->sa_data, ETH_ALEN); - - return ret; -} - -#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 - -static int -prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - u32 mlme, authen, dot1x, filter, wep; - - if (islpci_get_state(priv) < PRV_STATE_INIT) - return 0; - - wep = 1; /* For privacy invoked */ - filter = 1; /* Filter out all unencrypted frames */ - dot1x = 0x01; /* To enable eap filter */ - mlme = DOT11_MLME_EXTENDED; - authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ - - down_write(&priv->mib_sem); - priv->wpa = *uwrq; - - switch (priv->wpa) { - default: - case 0: /* Clears/disables WPA and friends */ - wep = 0; - filter = 0; /* Do not filter un-encrypted data */ - dot1x = 0; - mlme = DOT11_MLME_AUTO; - printk("%s: Disabling WPA\n", ndev->name); - break; - case 2: - case 1: /* WPA */ - printk("%s: Enabling WPA\n", ndev->name); - break; - } - up_write(&priv->mib_sem); - - mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); - mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep); - mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter); - mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); - mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme); - - return 0; -} - -static int -prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - *uwrq = priv->wpa; - return 0; -} - -static int -prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - priv->monitor_type = - (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211); - if (priv->iw_mode == IW_MODE_MONITOR) - priv->ndev->type = priv->monitor_type; - - return 0; -} - -static int -prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM); - return 0; -} - -static int -prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info, - __u32 * uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - - priv->priv_oid = *uwrq; - printk("%s: oid 0x%08X\n", ndev->name, *uwrq); - - return 0; -} - -static int -prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct islpci_mgmtframe *response; - int ret = -EIO; - - printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); - data->length = 0; - - if (islpci_get_state(priv) >= PRV_STATE_INIT) { - ret = - islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, - priv->priv_oid, extra, 256, - &response); - printk("%s: ret: %i\n", ndev->name, ret); - if (ret || !response - || response->header->operation == PIMFOR_OP_ERROR) { - if (response) { - islpci_mgt_release(response); - } - printk("%s: EIO\n", ndev->name); - ret = -EIO; - } - if (!ret) { - data->length = response->header->length; - memcpy(extra, response->data, data->length); - islpci_mgt_release(response); - printk("%s: len: %i\n", ndev->name, data->length); - } - } - - return ret; -} - -static int -prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - struct islpci_mgmtframe *response; - int ret = 0, response_op = PIMFOR_OP_ERROR; - - printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, - data->length); - - if (islpci_get_state(priv) >= PRV_STATE_INIT) { - ret = - islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, - priv->priv_oid, extra, data->length, - &response); - printk("%s: ret: %i\n", ndev->name, ret); - if (ret || !response - || response->header->operation == PIMFOR_OP_ERROR) { - if (response) { - islpci_mgt_release(response); - } - printk("%s: EIO\n", ndev->name); - ret = -EIO; - } - if (!ret) { - response_op = response->header->operation; - printk("%s: response_op: %i\n", ndev->name, - response_op); - islpci_mgt_release(response); - } - } - - return (ret ? ret : -EINPROGRESS); -} - -static int -prism54_set_spy(struct net_device *ndev, - struct iw_request_info *info, - union iwreq_data *uwrq, char *extra) -{ - islpci_private *priv = netdev_priv(ndev); - u32 u; - enum oid_num_t oid = OID_INL_CONFIG; - - down_write(&priv->mib_sem); - mgt_get(priv, OID_INL_CONFIG, &u); - - if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0)) - /* disable spy */ - u &= ~INL_CONFIG_RXANNEX; - else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0)) - /* enable spy */ - u |= INL_CONFIG_RXANNEX; - - mgt_set(priv, OID_INL_CONFIG, &u); - mgt_commit_list(priv, &oid, 1); - up_write(&priv->mib_sem); - - return iw_handler_set_spy(ndev, info, uwrq, extra); -} - -static const iw_handler prism54_handler[] = { - (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */ - (iw_handler) prism54_get_name, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */ - (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */ - (iw_handler) prism54_set_mode, /* SIOCSIWMODE */ - (iw_handler) prism54_get_mode, /* SIOCGIWMODE */ - (iw_handler) prism54_set_sens, /* SIOCSIWSENS */ - (iw_handler) prism54_get_sens, /* SIOCGIWSENS */ - (iw_handler) NULL, /* SIOCSIWRANGE */ - (iw_handler) prism54_get_range, /* SIOCGIWRANGE */ - (iw_handler) NULL, /* SIOCSIWPRIV */ - (iw_handler) NULL, /* SIOCGIWPRIV */ - (iw_handler) NULL, /* SIOCSIWSTATS */ - (iw_handler) NULL, /* SIOCGIWSTATS */ - prism54_set_spy, /* SIOCSIWSPY */ - iw_handler_get_spy, /* SIOCGIWSPY */ - iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ - iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ - (iw_handler) prism54_set_wap, /* SIOCSIWAP */ - (iw_handler) prism54_get_wap, /* SIOCGIWAP */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* SIOCGIWAPLIST deprecated */ - (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */ - (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */ - (iw_handler) prism54_set_essid, /* SIOCSIWESSID */ - (iw_handler) prism54_get_essid, /* SIOCGIWESSID */ - (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */ - (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) prism54_set_rate, /* SIOCSIWRATE */ - (iw_handler) prism54_get_rate, /* SIOCGIWRATE */ - (iw_handler) prism54_set_rts, /* SIOCSIWRTS */ - (iw_handler) prism54_get_rts, /* SIOCGIWRTS */ - (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */ - (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */ - (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */ - (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */ - (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */ - (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */ - (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */ - (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ - (iw_handler) NULL, /* SIOCSIWPOWER */ - (iw_handler) NULL, /* SIOCGIWPOWER */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */ - (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */ - (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */ - (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */ - (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */ - NULL, /* SIOCSIWPMKSA */ -}; - -/* The low order bit identify a SET (0) or a GET (1) ioctl. */ - -#define PRISM54_RESET SIOCIWFIRSTPRIV -#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1 -#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2 -#define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3 -#define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4 - -#define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6 - -#define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8 - -#define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10 - -#define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11 -#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 - -#define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14 -#define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15 -#define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16 - -#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17 -#define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18 -#define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20 -#define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22 - -#define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23 -#define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24 - -#define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } -#define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } -#define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } -#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x } - -#define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x) -#define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x) -#define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x) - -/* Note : limited to 128 private ioctls (wireless tools 26) */ - -static const struct iw_priv_args prism54_private_args[] = { -/*{ cmd, set_args, get_args, name } */ - {PRISM54_RESET, 0, 0, "reset"}, - {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_prismhdr"}, - {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, - "set_prismhdr"}, - {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "getPolicy"}, - {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, - "setPolicy"}, - {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"}, - {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, - "addMac"}, - {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, - "delMac"}, - {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, - "kickMac"}, - {PRISM54_KICK_ALL, 0, 0, "kickAll"}, - {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_wpa"}, - {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, - "set_wpa"}, - {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, - "dbg_oid"}, - {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"}, - {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"}, - /* --- sub-ioctls handlers --- */ - {PRISM54_GET_OID, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""}, - {PRISM54_SET_OID_U32, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, - {PRISM54_SET_OID_STR, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, - {PRISM54_SET_OID_ADDR, - IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, - /* --- sub-ioctls definitions --- */ - IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"), - IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"), - IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"), - IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"), - IWPRIV_U32(DOT11_OID_STATE, "state"), - IWPRIV_U32(DOT11_OID_AID, "aid"), - - IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"), - - IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"), - IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"), - IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"), - - IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"), - IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"), - IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"), - - IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"), - - IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"), - IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"), - IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"), - IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"), - IWPRIV_U32(DOT11_OID_PSM, "psm"), - - IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"), - IWPRIV_U32(DOT11_OID_CLIENTS, "clients"), - IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"), - IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"), - IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"), - IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"), - IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"), - IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"), - IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"), - IWPRIV_GET(DOT11_OID_RATES, "rates"), - IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"), - IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"), - IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"), - - IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"), - IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"), - IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"), - IWPRIV_U32(DOT11_OID_PROFILES, "profile"), - IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"), - IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"), - - IWPRIV_GET(DOT11_OID_BSSS, "bsss"), - IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"), - IWPRIV_U32(OID_INL_MODE, "mode"), - IWPRIV_U32(OID_INL_CONFIG, "config"), - IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"), - IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"), - IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"), -}; - -static const iw_handler prism54_private_handler[] = { - (iw_handler) prism54_reset, - (iw_handler) prism54_get_policy, - (iw_handler) prism54_set_policy, - (iw_handler) prism54_get_mac, - (iw_handler) prism54_add_mac, - (iw_handler) NULL, - (iw_handler) prism54_del_mac, - (iw_handler) NULL, - (iw_handler) prism54_kick_mac, - (iw_handler) NULL, - (iw_handler) prism54_kick_all, - (iw_handler) prism54_get_wpa, - (iw_handler) prism54_set_wpa, - (iw_handler) NULL, - (iw_handler) prism54_debug_oid, - (iw_handler) prism54_debug_get_oid, - (iw_handler) prism54_debug_set_oid, - (iw_handler) prism54_get_oid, - (iw_handler) prism54_set_u32, - (iw_handler) NULL, - (iw_handler) prism54_set_raw, - (iw_handler) NULL, - (iw_handler) prism54_set_raw, - (iw_handler) prism54_get_prismhdr, - (iw_handler) prism54_set_prismhdr, -}; - -const struct iw_handler_def prism54_handler_def = { - .num_standard = ARRAY_SIZE(prism54_handler), - .num_private = ARRAY_SIZE(prism54_private_handler), - .num_private_args = ARRAY_SIZE(prism54_private_args), - .standard = (iw_handler *) prism54_handler, - .private = (iw_handler *) prism54_private_handler, - .private_args = (struct iw_priv_args *) prism54_private_args, - .get_wireless_stats = prism54_get_wireless_stats, -}; diff --git a/drivers/net/wireless/intersil/prism54/isl_ioctl.h b/drivers/net/wireless/intersil/prism54/isl_ioctl.h deleted file mode 100644 index 3f85fd75ac19..000000000000 --- a/drivers/net/wireless/intersil/prism54/isl_ioctl.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2002 Intersil Americas Inc. - * (C) 2003 Aurelien Alleaume <slts@free.fr> - * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> - */ - -#ifndef _ISL_IOCTL_H -#define _ISL_IOCTL_H - -#include "islpci_mgt.h" -#include "islpci_dev.h" - -#include <net/iw_handler.h> /* New driver API */ - -#define SUPPORTED_WIRELESS_EXT 19 - -void prism54_mib_init(islpci_private *); - -struct iw_statistics *prism54_get_wireless_stats(struct net_device *); -void prism54_update_stats(struct work_struct *); - -void prism54_acl_init(struct islpci_acl *); -void prism54_acl_clean(struct islpci_acl *); - -void prism54_process_trap(struct work_struct *); - -void prism54_wpa_bss_ie_init(islpci_private *priv); -void prism54_wpa_bss_ie_clean(islpci_private *priv); - -int prism54_set_mac_address(struct net_device *, void *); - -extern const struct iw_handler_def prism54_handler_def; - -#endif /* _ISL_IOCTL_H */ diff --git a/drivers/net/wireless/intersil/prism54/isl_oid.h b/drivers/net/wireless/intersil/prism54/isl_oid.h deleted file mode 100644 index b889bb73a485..000000000000 --- a/drivers/net/wireless/intersil/prism54/isl_oid.h +++ /dev/null @@ -1,492 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> - * Copyright (C) 2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> - * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - */ - -#if !defined(_ISL_OID_H) -#define _ISL_OID_H - -/* - * MIB related constant and structure definitions for communicating - * with the device firmware - */ - -struct obj_ssid { - u8 length; - char octets[33]; -} __packed; - -struct obj_key { - u8 type; /* dot11_priv_t */ - u8 length; - char key[32]; -} __packed; - -struct obj_mlme { - u8 address[6]; - u16 id; - u16 state; - u16 code; -} __packed; - -struct obj_mlmeex { - u8 address[6]; - u16 id; - u16 state; - u16 code; - u16 size; - u8 data[]; -} __packed; - -struct obj_buffer { - u32 size; - u32 addr; /* 32bit bus address */ -} __packed; - -struct obj_bss { - u8 address[6]; - int:16; /* padding */ - - char state; - char reserved; - short age; - - char quality; - char rssi; - - struct obj_ssid ssid; - short channel; - char beacon_period; - char dtim_period; - short capinfo; - short rates; - short basic_rates; - int:16; /* padding */ -} __packed; - -struct obj_bsslist { - u32 nr; - struct obj_bss bsslist[]; -} __packed; - -struct obj_frequencies { - u16 nr; - u16 mhz[]; -} __packed; - -struct obj_attachment { - char type; - char reserved; - short id; - short size; - char data[]; -} __packed; - -/* - * in case everything's ok, the inlined function below will be - * optimized away by the compiler... - */ -static inline void -__bug_on_wrong_struct_sizes(void) -{ - BUILD_BUG_ON(sizeof (struct obj_ssid) != 34); - BUILD_BUG_ON(sizeof (struct obj_key) != 34); - BUILD_BUG_ON(sizeof (struct obj_mlme) != 12); - BUILD_BUG_ON(sizeof (struct obj_mlmeex) != 14); - BUILD_BUG_ON(sizeof (struct obj_buffer) != 8); - BUILD_BUG_ON(sizeof (struct obj_bss) != 60); - BUILD_BUG_ON(sizeof (struct obj_bsslist) != 4); - BUILD_BUG_ON(sizeof (struct obj_frequencies) != 2); -} - -enum dot11_state_t { - DOT11_STATE_NONE = 0, - DOT11_STATE_AUTHING = 1, - DOT11_STATE_AUTH = 2, - DOT11_STATE_ASSOCING = 3, - - DOT11_STATE_ASSOC = 5, - DOT11_STATE_IBSS = 6, - DOT11_STATE_WDS = 7 -}; - -enum dot11_bsstype_t { - DOT11_BSSTYPE_NONE = 0, - DOT11_BSSTYPE_INFRA = 1, - DOT11_BSSTYPE_IBSS = 2, - DOT11_BSSTYPE_ANY = 3 -}; - -enum dot11_auth_t { - DOT11_AUTH_NONE = 0, - DOT11_AUTH_OS = 1, - DOT11_AUTH_SK = 2, - DOT11_AUTH_BOTH = 3 -}; - -enum dot11_mlme_t { - DOT11_MLME_AUTO = 0, - DOT11_MLME_INTERMEDIATE = 1, - DOT11_MLME_EXTENDED = 2 -}; - -enum dot11_priv_t { - DOT11_PRIV_WEP = 0, - DOT11_PRIV_TKIP = 1 -}; - -/* Prism "Nitro" / Frameburst / "Packet Frame Grouping" - * Value is in microseconds. Represents the # microseconds - * the firmware will take to group frames before sending out then out - * together with a CSMA contention. Without this all frames are - * sent with a CSMA contention. - * Bibliography: - * https://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html - */ -enum dot11_maxframeburst_t { - /* Values for DOT11_OID_MAXFRAMEBURST */ - DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */ - DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */ - DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */ - DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max, - * Note: firmware allows for greater values. This is a - * recommended max. I'll update this as I find - * out what the real MAX is. Also note that you don't necessarily - * get better results with a greater value here. - */ -}; - -/* Support for 802.11 long and short frame preambles. - * Long preamble uses 128-bit sync field, 8-bit CRC - * Short preamble uses 56-bit sync field, 16-bit CRC - * - * 802.11a -- not sure, both optionally ? - * 802.11b supports long and optionally short - * 802.11g supports both */ -enum dot11_preamblesettings_t { - DOT11_PREAMBLESETTING_LONG = 0, - /* Allows *only* long 802.11 preambles */ - DOT11_PREAMBLESETTING_SHORT = 1, - /* Allows *only* short 802.11 preambles */ - DOT11_PREAMBLESETTING_DYNAMIC = 2 - /* AutomatiGically set */ -}; - -/* Support for 802.11 slot timing (time between packets). - * - * Long uses 802.11a slot timing (9 usec ?) - * Short uses 802.11b slot timing (20 use ?) */ -enum dot11_slotsettings_t { - DOT11_SLOTSETTINGS_LONG = 0, - /* Allows *only* long 802.11b slot timing */ - DOT11_SLOTSETTINGS_SHORT = 1, - /* Allows *only* long 802.11a slot timing */ - DOT11_SLOTSETTINGS_DYNAMIC = 2 - /* AutomatiGically set */ -}; - -/* All you need to know, ERP is "Extended Rate PHY". - * An Extended Rate PHY (ERP) STA or AP shall support three different - * preamble and header formats: - * Long preamble (refer to above) - * Short preamble (refer to above) - * OFDM preamble ( ? ) - * - * I'm assuming here Protection tells the AP - * to be careful, a STA which cannot handle the long pre-amble - * has joined. - */ -enum do11_nonerpstatus_t { - DOT11_ERPSTAT_NONEPRESENT = 0, - DOT11_ERPSTAT_USEPROTECTION = 1 -}; - -/* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-* - * The key here is DOT11 NON ERP NEVER protects against - * NON ERP STA's. You *don't* want this unless - * you know what you are doing. It means you will only - * get Extended Rate capabilities */ -enum dot11_nonerpprotection_t { - DOT11_NONERP_NEVER = 0, - DOT11_NONERP_ALWAYS = 1, - DOT11_NONERP_DYNAMIC = 2 -}; - -/* Preset OID configuration for 802.11 modes - * Note: DOT11_OID_CW[MIN|MAX] hold the values of the - * DCS MIN|MAX backoff used */ -enum dot11_profile_t { /* And set/allowed values */ - /* Allowed values for DOT11_OID_PROFILES */ - DOT11_PROFILE_B_ONLY = 0, - /* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps - * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC - * DOT11_OID_CWMIN: 31 - * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC - * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG - */ - DOT11_PROFILE_MIXED_G_WIFI = 1, - /* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs - * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC - * DOT11_OID_CWMIN: 15 - * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC - * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC - */ - DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */ - /* Same as Profile MIXED_G_WIFI */ - DOT11_PROFILE_G_ONLY = 3, - /* Same as Profile MIXED_G_WIFI */ - DOT11_PROFILE_TEST = 4, - /* Same as Profile MIXED_G_WIFI except: - * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT - * DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER - * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT - */ - DOT11_PROFILE_B_WIFI = 5, - /* Same as Profile B_ONLY */ - DOT11_PROFILE_A_ONLY = 6, - /* Same as Profile MIXED_G_WIFI except: - * DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs - */ - DOT11_PROFILE_MIXED_SHORT = 7 - /* Same as MIXED_G_WIFI */ -}; - - -/* The dot11d conformance level configures the 802.11d conformance levels. - * The following conformance levels exist:*/ -enum oid_inl_conformance_t { - OID_INL_CONFORMANCE_NONE = 0, /* Perform active scanning */ - OID_INL_CONFORMANCE_STRICT = 1, /* Strictly adhere to 802.11d */ - OID_INL_CONFORMANCE_FLEXIBLE = 2, /* Use passed 802.11d info to - * determine channel AND/OR just make assumption that active - * channels are valid channels */ -}; - -enum oid_inl_mode_t { - INL_MODE_NONE = -1, - INL_MODE_PROMISCUOUS = 0, - INL_MODE_CLIENT = 1, - INL_MODE_AP = 2, - INL_MODE_SNIFFER = 3 -}; - -enum oid_inl_config_t { - INL_CONFIG_NOTHING = 0x00, - INL_CONFIG_MANUALRUN = 0x01, - INL_CONFIG_FRAMETRAP = 0x02, - INL_CONFIG_RXANNEX = 0x04, - INL_CONFIG_TXANNEX = 0x08, - INL_CONFIG_WDS = 0x10 -}; - -enum oid_inl_phycap_t { - INL_PHYCAP_2400MHZ = 1, - INL_PHYCAP_5000MHZ = 2, - INL_PHYCAP_FAA = 0x80000000, /* Means card supports the FAA switch */ -}; - - -enum oid_num_t { - GEN_OID_MACADDRESS = 0, - GEN_OID_LINKSTATE, - GEN_OID_WATCHDOG, - GEN_OID_MIBOP, - GEN_OID_OPTIONS, - GEN_OID_LEDCONFIG, - - /* 802.11 */ - DOT11_OID_BSSTYPE, - DOT11_OID_BSSID, - DOT11_OID_SSID, - DOT11_OID_STATE, - DOT11_OID_AID, - DOT11_OID_COUNTRYSTRING, - DOT11_OID_SSIDOVERRIDE, - - DOT11_OID_MEDIUMLIMIT, - DOT11_OID_BEACONPERIOD, - DOT11_OID_DTIMPERIOD, - DOT11_OID_ATIMWINDOW, - DOT11_OID_LISTENINTERVAL, - DOT11_OID_CFPPERIOD, - DOT11_OID_CFPDURATION, - - DOT11_OID_AUTHENABLE, - DOT11_OID_PRIVACYINVOKED, - DOT11_OID_EXUNENCRYPTED, - DOT11_OID_DEFKEYID, - DOT11_OID_DEFKEYX, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ - DOT11_OID_STAKEY, - DOT11_OID_REKEYTHRESHOLD, - DOT11_OID_STASC, - - DOT11_OID_PRIVTXREJECTED, - DOT11_OID_PRIVRXPLAIN, - DOT11_OID_PRIVRXFAILED, - DOT11_OID_PRIVRXNOKEY, - - DOT11_OID_RTSTHRESH, - DOT11_OID_FRAGTHRESH, - DOT11_OID_SHORTRETRIES, - DOT11_OID_LONGRETRIES, - DOT11_OID_MAXTXLIFETIME, - DOT11_OID_MAXRXLIFETIME, - DOT11_OID_AUTHRESPTIMEOUT, - DOT11_OID_ASSOCRESPTIMEOUT, - - DOT11_OID_ALOFT_TABLE, - DOT11_OID_ALOFT_CTRL_TABLE, - DOT11_OID_ALOFT_RETREAT, - DOT11_OID_ALOFT_PROGRESS, - DOT11_OID_ALOFT_FIXEDRATE, - DOT11_OID_ALOFT_RSSIGRAPH, - DOT11_OID_ALOFT_CONFIG, - - DOT11_OID_VDCFX, - DOT11_OID_MAXFRAMEBURST, - - DOT11_OID_PSM, - DOT11_OID_CAMTIMEOUT, - DOT11_OID_RECEIVEDTIMS, - DOT11_OID_ROAMPREFERENCE, - - DOT11_OID_BRIDGELOCAL, - DOT11_OID_CLIENTS, - DOT11_OID_CLIENTSASSOCIATED, - DOT11_OID_CLIENTX, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ - - DOT11_OID_CLIENTFIND, - DOT11_OID_WDSLINKADD, - DOT11_OID_WDSLINKREMOVE, - DOT11_OID_EAPAUTHSTA, - DOT11_OID_EAPUNAUTHSTA, - DOT11_OID_DOT1XENABLE, - DOT11_OID_MICFAILURE, - DOT11_OID_REKEYINDICATE, - - DOT11_OID_MPDUTXSUCCESSFUL, - DOT11_OID_MPDUTXONERETRY, - DOT11_OID_MPDUTXMULTIPLERETRIES, - DOT11_OID_MPDUTXFAILED, - DOT11_OID_MPDURXSUCCESSFUL, - DOT11_OID_MPDURXDUPS, - DOT11_OID_RTSSUCCESSFUL, - DOT11_OID_RTSFAILED, - DOT11_OID_ACKFAILED, - DOT11_OID_FRAMERECEIVES, - DOT11_OID_FRAMEERRORS, - DOT11_OID_FRAMEABORTS, - DOT11_OID_FRAMEABORTSPHY, - - DOT11_OID_SLOTTIME, - DOT11_OID_CWMIN, /* MIN DCS backoff */ - DOT11_OID_CWMAX, /* MAX DCS backoff */ - DOT11_OID_ACKWINDOW, - DOT11_OID_ANTENNARX, - DOT11_OID_ANTENNATX, - DOT11_OID_ANTENNADIVERSITY, - DOT11_OID_CHANNEL, - DOT11_OID_EDTHRESHOLD, - DOT11_OID_PREAMBLESETTINGS, - DOT11_OID_RATES, - DOT11_OID_CCAMODESUPPORTED, - DOT11_OID_CCAMODE, - DOT11_OID_RSSIVECTOR, - DOT11_OID_OUTPUTPOWERTABLE, - DOT11_OID_OUTPUTPOWER, - DOT11_OID_SUPPORTEDRATES, - DOT11_OID_FREQUENCY, - DOT11_OID_SUPPORTEDFREQUENCIES, - DOT11_OID_NOISEFLOOR, - DOT11_OID_FREQUENCYACTIVITY, - DOT11_OID_IQCALIBRATIONTABLE, - DOT11_OID_NONERPPROTECTION, - DOT11_OID_SLOTSETTINGS, - DOT11_OID_NONERPTIMEOUT, - DOT11_OID_PROFILES, - DOT11_OID_EXTENDEDRATES, - - DOT11_OID_DEAUTHENTICATE, - DOT11_OID_AUTHENTICATE, - DOT11_OID_DISASSOCIATE, - DOT11_OID_ASSOCIATE, - DOT11_OID_SCAN, - DOT11_OID_BEACON, - DOT11_OID_PROBE, - DOT11_OID_DEAUTHENTICATEEX, - DOT11_OID_AUTHENTICATEEX, - DOT11_OID_DISASSOCIATEEX, - DOT11_OID_ASSOCIATEEX, - DOT11_OID_REASSOCIATE, - DOT11_OID_REASSOCIATEEX, - - DOT11_OID_NONERPSTATUS, - - DOT11_OID_STATIMEOUT, - DOT11_OID_MLMEAUTOLEVEL, - DOT11_OID_BSSTIMEOUT, - DOT11_OID_ATTACHMENT, - DOT11_OID_PSMBUFFER, - - DOT11_OID_BSSS, - DOT11_OID_BSSX, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ - DOT11_OID_BSSFIND, - DOT11_OID_BSSLIST, - - OID_INL_TUNNEL, - OID_INL_MEMADDR, - OID_INL_MEMORY, - OID_INL_MODE, - OID_INL_COMPONENT_NR, - OID_INL_VERSION, - OID_INL_INTERFACE_ID, - OID_INL_COMPONENT_ID, - OID_INL_CONFIG, - OID_INL_DOT11D_CONFORMANCE, - OID_INL_PHYCAPABILITIES, - OID_INL_OUTPUTPOWER, - - OID_NUM_LAST -}; - -#define OID_FLAG_CACHED 0x80 -#define OID_FLAG_TYPE 0x7f - -#define OID_TYPE_U32 0x01 -#define OID_TYPE_SSID 0x02 -#define OID_TYPE_KEY 0x03 -#define OID_TYPE_BUFFER 0x04 -#define OID_TYPE_BSS 0x05 -#define OID_TYPE_BSSLIST 0x06 -#define OID_TYPE_FREQUENCIES 0x07 -#define OID_TYPE_MLME 0x08 -#define OID_TYPE_MLMEEX 0x09 -#define OID_TYPE_ADDR 0x0A -#define OID_TYPE_RAW 0x0B -#define OID_TYPE_ATTACH 0x0C - -/* OID_TYPE_MLMEEX is special because of a variable size field when sending. - * Not yet implemented (not used in driver anyway). - */ - -struct oid_t { - enum oid_num_t oid; - short range; /* to define a range of oid */ - short size; /* max size of the associated data */ - char flags; -}; - -union oid_res_t { - void *ptr; - u32 u; -}; - -#define IWMAX_BITRATES 20 -#define IWMAX_BSS 24 -#define IWMAX_FREQ 30 -#define PRIV_STR_SIZE 1024 - -#endif /* !defined(_ISL_OID_H) */ -/* EOF */ diff --git a/drivers/net/wireless/intersil/prism54/islpci_dev.c b/drivers/net/wireless/intersil/prism54/islpci_dev.c deleted file mode 100644 index 8eb6d5e4bd57..000000000000 --- a/drivers/net/wireless/intersil/prism54/islpci_dev.c +++ /dev/null @@ -1,951 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2002 Intersil Americas Inc. - * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> - * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> - */ - -#include <linux/hardirq.h> -#include <linux/module.h> -#include <linux/slab.h> - -#include <linux/netdevice.h> -#include <linux/ethtool.h> -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/etherdevice.h> -#include <linux/delay.h> -#include <linux/if_arp.h> - -#include <asm/io.h> - -#include "prismcompat.h" -#include "isl_38xx.h" -#include "isl_ioctl.h" -#include "islpci_dev.h" -#include "islpci_mgt.h" -#include "islpci_eth.h" -#include "oid_mgt.h" - -#define ISL3877_IMAGE_FILE "isl3877" -#define ISL3886_IMAGE_FILE "isl3886" -#define ISL3890_IMAGE_FILE "isl3890" -MODULE_FIRMWARE(ISL3877_IMAGE_FILE); -MODULE_FIRMWARE(ISL3886_IMAGE_FILE); -MODULE_FIRMWARE(ISL3890_IMAGE_FILE); - -static int prism54_bring_down(islpci_private *); -static int islpci_alloc_memory(islpci_private *); - -/* Temporary dummy MAC address to use until firmware is loaded. - * The idea there is that some tools (such as nameif) may query - * the MAC address before the netdev is 'open'. By using a valid - * OUI prefix, they can process the netdev properly. - * Of course, this is not the final/real MAC address. It doesn't - * matter, as you are suppose to be able to change it anytime via - * ndev->set_mac_address. Jean II */ -static const unsigned char dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 }; - -static int -isl_upload_firmware(islpci_private *priv) -{ - u32 reg, rc; - void __iomem *device_base = priv->device_base; - - /* clear the RAMBoot and the Reset bit */ - reg = readl(device_base + ISL38XX_CTRL_STAT_REG); - reg &= ~ISL38XX_CTRL_STAT_RESET; - reg &= ~ISL38XX_CTRL_STAT_RAMBOOT; - writel(reg, device_base + ISL38XX_CTRL_STAT_REG); - wmb(); - udelay(ISL38XX_WRITEIO_DELAY); - - /* set the Reset bit without reading the register ! */ - reg |= ISL38XX_CTRL_STAT_RESET; - writel(reg, device_base + ISL38XX_CTRL_STAT_REG); - wmb(); - udelay(ISL38XX_WRITEIO_DELAY); - - /* clear the Reset bit */ - reg &= ~ISL38XX_CTRL_STAT_RESET; - writel(reg, device_base + ISL38XX_CTRL_STAT_REG); - wmb(); - - /* wait a while for the device to reboot */ - mdelay(50); - - { - const struct firmware *fw_entry = NULL; - long fw_len; - const u32 *fw_ptr; - - rc = request_firmware(&fw_entry, priv->firmware, PRISM_FW_PDEV); - if (rc) { - printk(KERN_ERR - "%s: request_firmware() failed for '%s'\n", - "prism54", priv->firmware); - return rc; - } - /* prepare the Direct Memory Base register */ - reg = ISL38XX_DEV_FIRMWARE_ADDRES; - - fw_ptr = (u32 *) fw_entry->data; - fw_len = fw_entry->size; - - if (fw_len % 4) { - printk(KERN_ERR - "%s: firmware '%s' size is not multiple of 32bit, aborting!\n", - "prism54", priv->firmware); - release_firmware(fw_entry); - return -EILSEQ; /* Illegal byte sequence */; - } - - while (fw_len > 0) { - long _fw_len = - (fw_len > - ISL38XX_MEMORY_WINDOW_SIZE) ? - ISL38XX_MEMORY_WINDOW_SIZE : fw_len; - u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; - - /* set the card's base address for writing the data */ - isl38xx_w32_flush(device_base, reg, - ISL38XX_DIR_MEM_BASE_REG); - wmb(); /* be paranoid */ - - /* increment the write address for next iteration */ - reg += _fw_len; - fw_len -= _fw_len; - - /* write the data to the Direct Memory Window 32bit-wise */ - /* memcpy_toio() doesn't guarantee 32bit writes :-| */ - while (_fw_len > 0) { - /* use non-swapping writel() */ - __raw_writel(*fw_ptr, dev_fw_ptr); - fw_ptr++, dev_fw_ptr++; - _fw_len -= 4; - } - - /* flush PCI posting */ - (void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH); - wmb(); /* be paranoid again */ - - BUG_ON(_fw_len != 0); - } - - BUG_ON(fw_len != 0); - - /* Firmware version is at offset 40 (also for "newmac") */ - printk(KERN_DEBUG "%s: firmware version: %.8s\n", - priv->ndev->name, fw_entry->data + 40); - - release_firmware(fw_entry); - } - - /* now reset the device - * clear the Reset & ClkRun bit, set the RAMBoot bit */ - reg = readl(device_base + ISL38XX_CTRL_STAT_REG); - reg &= ~ISL38XX_CTRL_STAT_CLKRUN; - reg &= ~ISL38XX_CTRL_STAT_RESET; - reg |= ISL38XX_CTRL_STAT_RAMBOOT; - isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG); - wmb(); - udelay(ISL38XX_WRITEIO_DELAY); - - /* set the reset bit latches the host override and RAMBoot bits - * into the device for operation when the reset bit is reset */ - reg |= ISL38XX_CTRL_STAT_RESET; - writel(reg, device_base + ISL38XX_CTRL_STAT_REG); - /* don't do flush PCI posting here! */ - wmb(); - udelay(ISL38XX_WRITEIO_DELAY); - - /* clear the reset bit should start the whole circus */ - reg &= ~ISL38XX_CTRL_STAT_RESET; - writel(reg, device_base + ISL38XX_CTRL_STAT_REG); - /* don't do flush PCI posting here! */ - wmb(); - udelay(ISL38XX_WRITEIO_DELAY); - - return 0; -} - -/****************************************************************************** - Device Interrupt Handler -******************************************************************************/ - -irqreturn_t -islpci_interrupt(int irq, void *config) -{ - u32 reg; - islpci_private *priv = config; - struct net_device *ndev = priv->ndev; - void __iomem *device = priv->device_base; - int powerstate = ISL38XX_PSM_POWERSAVE_STATE; - - /* lock the interrupt handler */ - spin_lock(&priv->slock); - - /* received an interrupt request on a shared IRQ line - * first check whether the device is in sleep mode */ - reg = readl(device + ISL38XX_CTRL_STAT_REG); - if (reg & ISL38XX_CTRL_STAT_SLEEPMODE) - /* device is in sleep mode, IRQ was generated by someone else */ - { -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); -#endif - spin_unlock(&priv->slock); - return IRQ_NONE; - } - - - /* check whether there is any source of interrupt on the device */ - reg = readl(device + ISL38XX_INT_IDENT_REG); - - /* also check the contents of the Interrupt Enable Register, because this - * will filter out interrupt sources from other devices on the same irq ! */ - reg &= readl(device + ISL38XX_INT_EN_REG); - reg &= ISL38XX_INT_SOURCES; - - if (reg != 0) { - if (islpci_get_state(priv) != PRV_STATE_SLEEP) - powerstate = ISL38XX_PSM_ACTIVE_STATE; - - /* reset the request bits in the Identification register */ - isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG); - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, - "IRQ: Identification register 0x%p 0x%x\n", device, reg); -#endif - - /* check for each bit in the register separately */ - if (reg & ISL38XX_INT_IDENT_UPDATE) { -#if VERBOSE > SHOW_ERROR_MESSAGES - /* Queue has been updated */ - DEBUG(SHOW_TRACING, "IRQ: Update flag\n"); - - DEBUG(SHOW_QUEUE_INDEXES, - "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n", - le32_to_cpu(priv->control_block-> - driver_curr_frag[0]), - le32_to_cpu(priv->control_block-> - driver_curr_frag[1]), - le32_to_cpu(priv->control_block-> - driver_curr_frag[2]), - le32_to_cpu(priv->control_block-> - driver_curr_frag[3]), - le32_to_cpu(priv->control_block-> - driver_curr_frag[4]), - le32_to_cpu(priv->control_block-> - driver_curr_frag[5]) - ); - - DEBUG(SHOW_QUEUE_INDEXES, - "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n", - le32_to_cpu(priv->control_block-> - device_curr_frag[0]), - le32_to_cpu(priv->control_block-> - device_curr_frag[1]), - le32_to_cpu(priv->control_block-> - device_curr_frag[2]), - le32_to_cpu(priv->control_block-> - device_curr_frag[3]), - le32_to_cpu(priv->control_block-> - device_curr_frag[4]), - le32_to_cpu(priv->control_block-> - device_curr_frag[5]) - ); -#endif - - /* cleanup the data low transmit queue */ - islpci_eth_cleanup_transmit(priv, priv->control_block); - - /* device is in active state, update the - * powerstate flag if necessary */ - powerstate = ISL38XX_PSM_ACTIVE_STATE; - - /* check all three queues in priority order - * call the PIMFOR receive function until the - * queue is empty */ - if (isl38xx_in_queue(priv->control_block, - ISL38XX_CB_RX_MGMTQ) != 0) { -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, - "Received frame in Management Queue\n"); -#endif - islpci_mgt_receive(ndev); - - islpci_mgt_cleanup_transmit(ndev); - - /* Refill slots in receive queue */ - islpci_mgmt_rx_fill(ndev); - - /* no need to trigger the device, next - islpci_mgt_transaction does it */ - } - - while (isl38xx_in_queue(priv->control_block, - ISL38XX_CB_RX_DATA_LQ) != 0) { -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, - "Received frame in Data Low Queue\n"); -#endif - islpci_eth_receive(priv); - } - - /* check whether the data transmit queues were full */ - if (priv->data_low_tx_full) { - /* check whether the transmit is not full anymore */ - if (ISL38XX_CB_TX_QSIZE - - isl38xx_in_queue(priv->control_block, - ISL38XX_CB_TX_DATA_LQ) >= - ISL38XX_MIN_QTHRESHOLD) { - /* nope, the driver is ready for more network frames */ - netif_wake_queue(priv->ndev); - - /* reset the full flag */ - priv->data_low_tx_full = 0; - } - } - } - - if (reg & ISL38XX_INT_IDENT_INIT) { - /* Device has been initialized */ -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, - "IRQ: Init flag, device initialized\n"); -#endif - wake_up(&priv->reset_done); - } - - if (reg & ISL38XX_INT_IDENT_SLEEP) { - /* Device intends to move to powersave state */ -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "IRQ: Sleep flag\n"); -#endif - isl38xx_handle_sleep_request(priv->control_block, - &powerstate, - priv->device_base); - } - - if (reg & ISL38XX_INT_IDENT_WAKEUP) { - /* Device has been woken up to active state */ -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "IRQ: Wakeup flag\n"); -#endif - - isl38xx_handle_wakeup(priv->control_block, - &powerstate, priv->device_base); - } - } else { -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); -#endif - spin_unlock(&priv->slock); - return IRQ_NONE; - } - - /* sleep -> ready */ - if (islpci_get_state(priv) == PRV_STATE_SLEEP - && powerstate == ISL38XX_PSM_ACTIVE_STATE) - islpci_set_state(priv, PRV_STATE_READY); - - /* !sleep -> sleep */ - if (islpci_get_state(priv) != PRV_STATE_SLEEP - && powerstate == ISL38XX_PSM_POWERSAVE_STATE) - islpci_set_state(priv, PRV_STATE_SLEEP); - - /* unlock the interrupt handler */ - spin_unlock(&priv->slock); - - return IRQ_HANDLED; -} - -/****************************************************************************** - Network Interface Control & Statistical functions -******************************************************************************/ -static int -islpci_open(struct net_device *ndev) -{ - u32 rc; - islpci_private *priv = netdev_priv(ndev); - - /* reset data structures, upload firmware and reset device */ - rc = islpci_reset(priv,1); - if (rc) { - prism54_bring_down(priv); - return rc; /* Returns informative message */ - } - - netif_start_queue(ndev); - - /* Turn off carrier if in STA or Ad-hoc mode. It will be turned on - * once the firmware receives a trap of being associated - * (GEN_OID_LINKSTATE). In other modes (AP or WDS or monitor) we - * should just leave the carrier on as its expected the firmware - * won't send us a trigger. */ - if (priv->iw_mode == IW_MODE_INFRA || priv->iw_mode == IW_MODE_ADHOC) - netif_carrier_off(ndev); - else - netif_carrier_on(ndev); - - return 0; -} - -static int -islpci_close(struct net_device *ndev) -{ - islpci_private *priv = netdev_priv(ndev); - - printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name); - - netif_stop_queue(ndev); - - return prism54_bring_down(priv); -} - -static int -prism54_bring_down(islpci_private *priv) -{ - void __iomem *device_base = priv->device_base; - u32 reg; - /* we are going to shutdown the device */ - islpci_set_state(priv, PRV_STATE_PREBOOT); - - /* disable all device interrupts in case they weren't */ - isl38xx_disable_interrupts(priv->device_base); - - /* For safety reasons, we may want to ensure that no DMA transfer is - * currently in progress by emptying the TX and RX queues. */ - - /* wait until interrupts have finished executing on other CPUs */ - synchronize_irq(priv->pdev->irq); - - reg = readl(device_base + ISL38XX_CTRL_STAT_REG); - reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT); - writel(reg, device_base + ISL38XX_CTRL_STAT_REG); - wmb(); - udelay(ISL38XX_WRITEIO_DELAY); - - reg |= ISL38XX_CTRL_STAT_RESET; - writel(reg, device_base + ISL38XX_CTRL_STAT_REG); - wmb(); - udelay(ISL38XX_WRITEIO_DELAY); - - /* clear the Reset bit */ - reg &= ~ISL38XX_CTRL_STAT_RESET; - writel(reg, device_base + ISL38XX_CTRL_STAT_REG); - wmb(); - - /* wait a while for the device to reset */ - schedule_timeout_uninterruptible(msecs_to_jiffies(50)); - - return 0; -} - -static int -islpci_upload_fw(islpci_private *priv) -{ - islpci_state_t old_state; - u32 rc; - - old_state = islpci_set_state(priv, PRV_STATE_BOOT); - - printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name); - - rc = isl_upload_firmware(priv); - if (rc) { - /* error uploading the firmware */ - printk(KERN_ERR "%s: could not upload firmware ('%s')\n", - priv->ndev->name, priv->firmware); - - islpci_set_state(priv, old_state); - return rc; - } - - printk(KERN_DEBUG "%s: firmware upload complete\n", - priv->ndev->name); - - islpci_set_state(priv, PRV_STATE_POSTBOOT); - - return 0; -} - -static int -islpci_reset_if(islpci_private *priv) -{ - long remaining; - int result = -ETIME; - int count; - - DEFINE_WAIT(wait); - prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE); - - /* now the last step is to reset the interface */ - isl38xx_interface_reset(priv->device_base, priv->device_host_address); - islpci_set_state(priv, PRV_STATE_PREINIT); - - for(count = 0; count < 2 && result; count++) { - /* The software reset acknowledge needs about 220 msec here. - * Be conservative and wait for up to one second. */ - - remaining = schedule_timeout_uninterruptible(HZ); - - if(remaining > 0) { - result = 0; - break; - } - - /* If we're here it's because our IRQ hasn't yet gone through. - * Retry a bit more... - */ - printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n", - priv->ndev->name); - } - - finish_wait(&priv->reset_done, &wait); - - if (result) { - printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); - return result; - } - - islpci_set_state(priv, PRV_STATE_INIT); - - /* Now that the device is 100% up, let's allow - * for the other interrupts -- - * NOTE: this is not *yet* true since we've only allowed the - * INIT interrupt on the IRQ line. We can perhaps poll - * the IRQ line until we know for sure the reset went through */ - isl38xx_enable_common_interrupts(priv->device_base); - - down_write(&priv->mib_sem); - result = mgt_commit(priv); - if (result) { - printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); - up_write(&priv->mib_sem); - return result; - } - up_write(&priv->mib_sem); - - islpci_set_state(priv, PRV_STATE_READY); - - printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name); - return 0; -} - -int -islpci_reset(islpci_private *priv, int reload_firmware) -{ - isl38xx_control_block *cb = /* volatile not needed */ - (isl38xx_control_block *) priv->control_block; - unsigned counter; - int rc; - - if (reload_firmware) - islpci_set_state(priv, PRV_STATE_PREBOOT); - else - islpci_set_state(priv, PRV_STATE_POSTBOOT); - - printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name); - - /* disable all device interrupts in case they weren't */ - isl38xx_disable_interrupts(priv->device_base); - - /* flush all management queues */ - priv->index_mgmt_tx = 0; - priv->index_mgmt_rx = 0; - - /* clear the indexes in the frame pointer */ - for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { - cb->driver_curr_frag[counter] = cpu_to_le32(0); - cb->device_curr_frag[counter] = cpu_to_le32(0); - } - - /* reset the mgmt receive queue */ - for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { - isl38xx_fragment *frag = &cb->rx_data_mgmt[counter]; - frag->size = cpu_to_le16(MGMT_FRAME_SIZE); - frag->flags = 0; - frag->address = cpu_to_le32(priv->mgmt_rx[counter].pci_addr); - } - - for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { - cb->rx_data_low[counter].address = - cpu_to_le32((u32) priv->pci_map_rx_address[counter]); - } - - /* since the receive queues are filled with empty fragments, now we can - * set the corresponding indexes in the Control Block */ - priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] = - cpu_to_le32(ISL38XX_CB_RX_QSIZE); - priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = - cpu_to_le32(ISL38XX_CB_MGMT_QSIZE); - - /* reset the remaining real index registers and full flags */ - priv->free_data_rx = 0; - priv->free_data_tx = 0; - priv->data_low_tx_full = 0; - - if (reload_firmware) { /* Should we load the firmware ? */ - /* now that the data structures are cleaned up, upload - * firmware and reset interface */ - rc = islpci_upload_fw(priv); - if (rc) { - printk(KERN_ERR "%s: islpci_reset: failure\n", - priv->ndev->name); - return rc; - } - } - - /* finally reset interface */ - rc = islpci_reset_if(priv); - if (rc) - printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); - return rc; -} - -/****************************************************************************** - Network device configuration functions -******************************************************************************/ -static int -islpci_alloc_memory(islpci_private *priv) -{ - int counter; - -#if VERBOSE > SHOW_ERROR_MESSAGES - printk(KERN_DEBUG "islpci_alloc_memory\n"); -#endif - - /* remap the PCI device base address to accessible */ - if (!(priv->device_base = - ioremap(pci_resource_start(priv->pdev, 0), - ISL38XX_PCI_MEM_SIZE))) { - /* error in remapping the PCI device memory address range */ - printk(KERN_ERR "PCI memory remapping failed\n"); - return -1; - } - - /* memory layout for consistent DMA region: - * - * Area 1: Control Block for the device interface - * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that - * the number of supported stations in the AP determines the minimal - * size of the buffer ! - */ - - /* perform the allocation */ - priv->driver_mem_address = dma_alloc_coherent(&priv->pdev->dev, - HOST_MEM_BLOCK, - &priv->device_host_address, - GFP_KERNEL); - - if (!priv->driver_mem_address) { - /* error allocating the block of PCI memory */ - printk(KERN_ERR "%s: could not allocate DMA memory, aborting!", - "prism54"); - return -1; - } - - /* assign the Control Block to the first address of the allocated area */ - priv->control_block = - (isl38xx_control_block *) priv->driver_mem_address; - - /* set the Power Save Buffer pointer directly behind the CB */ - priv->device_psm_buffer = - priv->device_host_address + CONTROL_BLOCK_SIZE; - - /* make sure all buffer pointers are initialized */ - for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { - priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0); - priv->control_block->device_curr_frag[counter] = cpu_to_le32(0); - } - - priv->index_mgmt_rx = 0; - memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx)); - memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx)); - - /* allocate rx queue for management frames */ - if (islpci_mgmt_rx_fill(priv->ndev) < 0) - goto out_free; - - /* now get the data rx skb's */ - memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx)); - memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address)); - - for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { - struct sk_buff *skb; - - /* allocate an sk_buff for received data frames storage - * each frame on receive size consists of 1 fragment - * include any required allignment operations */ - if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) { - /* error allocating an sk_buff structure elements */ - printk(KERN_ERR "Error allocating skb.\n"); - skb = NULL; - goto out_free; - } - skb_reserve(skb, (4 - (long) skb->data) & 0x03); - /* add the new allocated sk_buff to the buffer array */ - priv->data_low_rx[counter] = skb; - - /* map the allocated skb data area to pci */ - priv->pci_map_rx_address[counter] = - dma_map_single(&priv->pdev->dev, (void *)skb->data, - MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); - if (dma_mapping_error(&priv->pdev->dev, priv->pci_map_rx_address[counter])) { - priv->pci_map_rx_address[counter] = 0; - /* error mapping the buffer to device - accessible memory address */ - printk(KERN_ERR "failed to map skb DMA'able\n"); - goto out_free; - } - } - - prism54_acl_init(&priv->acl); - prism54_wpa_bss_ie_init(priv); - if (mgt_init(priv)) - goto out_free; - - return 0; - out_free: - islpci_free_memory(priv); - return -1; -} - -int -islpci_free_memory(islpci_private *priv) -{ - int counter; - - if (priv->device_base) - iounmap(priv->device_base); - priv->device_base = NULL; - - /* free consistent DMA area... */ - if (priv->driver_mem_address) - dma_free_coherent(&priv->pdev->dev, HOST_MEM_BLOCK, - priv->driver_mem_address, - priv->device_host_address); - - /* clear some dangling pointers */ - priv->driver_mem_address = NULL; - priv->device_host_address = 0; - priv->device_psm_buffer = 0; - priv->control_block = NULL; - - /* clean up mgmt rx buffers */ - for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { - struct islpci_membuf *buf = &priv->mgmt_rx[counter]; - if (buf->pci_addr) - dma_unmap_single(&priv->pdev->dev, buf->pci_addr, - buf->size, DMA_FROM_DEVICE); - buf->pci_addr = 0; - kfree(buf->mem); - buf->size = 0; - buf->mem = NULL; - } - - /* clean up data rx buffers */ - for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { - if (priv->pci_map_rx_address[counter]) - dma_unmap_single(&priv->pdev->dev, - priv->pci_map_rx_address[counter], - MAX_FRAGMENT_SIZE_RX + 2, - DMA_FROM_DEVICE); - priv->pci_map_rx_address[counter] = 0; - - if (priv->data_low_rx[counter]) - dev_kfree_skb(priv->data_low_rx[counter]); - priv->data_low_rx[counter] = NULL; - } - - /* Free the access control list and the WPA list */ - prism54_acl_clean(&priv->acl); - prism54_wpa_bss_ie_clean(priv); - mgt_clean(priv); - - return 0; -} - -#if 0 -static void -islpci_set_multicast_list(struct net_device *dev) -{ - /* put device into promisc mode and let network layer handle it */ -} -#endif - -static void islpci_ethtool_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); -} - -static const struct ethtool_ops islpci_ethtool_ops = { - .get_drvinfo = islpci_ethtool_get_drvinfo, -}; - -static const struct net_device_ops islpci_netdev_ops = { - .ndo_open = islpci_open, - .ndo_stop = islpci_close, - .ndo_start_xmit = islpci_eth_transmit, - .ndo_tx_timeout = islpci_eth_tx_timeout, - .ndo_set_mac_address = prism54_set_mac_address, - .ndo_validate_addr = eth_validate_addr, -}; - -static struct device_type wlan_type = { - .name = "wlan", -}; - -struct net_device * -islpci_setup(struct pci_dev *pdev) -{ - islpci_private *priv; - struct net_device *ndev = alloc_etherdev(sizeof (islpci_private)); - - if (!ndev) - return ndev; - - pci_set_drvdata(pdev, ndev); - SET_NETDEV_DEV(ndev, &pdev->dev); - SET_NETDEV_DEVTYPE(ndev, &wlan_type); - - /* setup the structure members */ - ndev->base_addr = pci_resource_start(pdev, 0); - ndev->irq = pdev->irq; - - /* initialize the function pointers */ - ndev->netdev_ops = &islpci_netdev_ops; - ndev->wireless_handlers = &prism54_handler_def; - ndev->ethtool_ops = &islpci_ethtool_ops; - - /* ndev->set_multicast_list = &islpci_set_multicast_list; */ - ndev->addr_len = ETH_ALEN; - /* Get a non-zero dummy MAC address for nameif. Jean II */ - memcpy(ndev->dev_addr, dummy_mac, ETH_ALEN); - - ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT; - - /* allocate a private device structure to the network device */ - priv = netdev_priv(ndev); - priv->ndev = ndev; - priv->pdev = pdev; - priv->monitor_type = ARPHRD_IEEE80211; - priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? - priv->monitor_type : ARPHRD_ETHER; - - /* Add pointers to enable iwspy support. */ - priv->wireless_data.spy_data = &priv->spy_data; - ndev->wireless_data = &priv->wireless_data; - - /* save the start and end address of the PCI memory area */ - ndev->mem_start = (unsigned long) priv->device_base; - ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base); -#endif - - init_waitqueue_head(&priv->reset_done); - - /* init the queue read locks, process wait counter */ - mutex_init(&priv->mgmt_lock); - priv->mgmt_received = NULL; - init_waitqueue_head(&priv->mgmt_wqueue); - mutex_init(&priv->stats_lock); - spin_lock_init(&priv->slock); - - /* init state machine with off#1 state */ - priv->state = PRV_STATE_OFF; - priv->state_off = 1; - - /* initialize workqueue's */ - INIT_WORK(&priv->stats_work, prism54_update_stats); - priv->stats_timestamp = 0; - - INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake); - priv->reset_task_pending = 0; - - /* allocate various memory areas */ - if (islpci_alloc_memory(priv)) - goto do_free_netdev; - - /* select the firmware file depending on the device id */ - switch (pdev->device) { - case 0x3877: - strcpy(priv->firmware, ISL3877_IMAGE_FILE); - break; - - case 0x3886: - strcpy(priv->firmware, ISL3886_IMAGE_FILE); - break; - - default: - strcpy(priv->firmware, ISL3890_IMAGE_FILE); - break; - } - - if (register_netdev(ndev)) { - DEBUG(SHOW_ERROR_MESSAGES, - "ERROR: register_netdev() failed\n"); - goto do_islpci_free_memory; - } - - return ndev; - - do_islpci_free_memory: - islpci_free_memory(priv); - do_free_netdev: - free_netdev(ndev); - priv = NULL; - return NULL; -} - -islpci_state_t -islpci_set_state(islpci_private *priv, islpci_state_t new_state) -{ - islpci_state_t old_state; - - /* lock */ - old_state = priv->state; - - /* this means either a race condition or some serious error in - * the driver code */ - switch (new_state) { - case PRV_STATE_OFF: - priv->state_off++; - fallthrough; - default: - priv->state = new_state; - break; - - case PRV_STATE_PREBOOT: - /* there are actually many off-states, enumerated by - * state_off */ - if (old_state == PRV_STATE_OFF) - priv->state_off--; - - /* only if hw_unavailable is zero now it means we either - * were in off#1 state, or came here from - * somewhere else */ - if (!priv->state_off) - priv->state = new_state; - break; - } -#if 0 - printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n", - priv->ndev->name, old_state, new_state, priv->state_off); -#endif - - /* invariants */ - BUG_ON(priv->state_off < 0); - BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF)); - BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF)); - - /* unlock */ - return old_state; -} diff --git a/drivers/net/wireless/intersil/prism54/islpci_dev.h b/drivers/net/wireless/intersil/prism54/islpci_dev.h deleted file mode 100644 index 4753418dce62..000000000000 --- a/drivers/net/wireless/intersil/prism54/islpci_dev.h +++ /dev/null @@ -1,204 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2002 Intersil Americas Inc. - * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> - * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> - * Copyright (C) 2003 Aurelien Alleaume <slts@free.fr> - */ - -#ifndef _ISLPCI_DEV_H -#define _ISLPCI_DEV_H - -#include <linux/irqreturn.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> -#include <linux/list.h> -#include <linux/mutex.h> - -#include "isl_38xx.h" -#include "isl_oid.h" -#include "islpci_mgt.h" - -/* some states might not be superflous and may be removed when - design is finalized (hvr) */ -typedef enum { - PRV_STATE_OFF = 0, /* this means hw_unavailable is != 0 */ - PRV_STATE_PREBOOT, /* we are in a pre-boot state (empty RAM) */ - PRV_STATE_BOOT, /* boot state (fw upload, run fw) */ - PRV_STATE_POSTBOOT, /* after boot state, need reset now */ - PRV_STATE_PREINIT, /* pre-init state */ - PRV_STATE_INIT, /* init state (restore MIB backup to device) */ - PRV_STATE_READY, /* driver&device are in operational state */ - PRV_STATE_SLEEP /* device in sleep mode */ -} islpci_state_t; - -/* ACL using MAC address */ -struct mac_entry { - struct list_head _list; - char addr[ETH_ALEN]; -}; - -struct islpci_acl { - enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy; - struct list_head mac_list; /* a list of mac_entry */ - int size; /* size of queue */ - struct mutex lock; /* accessed in ioctls and trap_work */ -}; - -struct islpci_membuf { - int size; /* size of memory */ - void *mem; /* address of memory as seen by CPU */ - dma_addr_t pci_addr; /* address of memory as seen by device */ -}; - -#define MAX_BSS_WPA_IE_COUNT 64 -#define MAX_WPA_IE_LEN 64 -struct islpci_bss_wpa_ie { - struct list_head list; - unsigned long last_update; - u8 bssid[ETH_ALEN]; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - -}; - -typedef struct { - spinlock_t slock; /* generic spinlock; */ - - u32 priv_oid; - - /* our mib cache */ - u32 iw_mode; - struct rw_semaphore mib_sem; - void **mib; - char nickname[IW_ESSID_MAX_SIZE+1]; - - /* Take care of the wireless stats */ - struct work_struct stats_work; - struct mutex stats_lock; - /* remember when we last updated the stats */ - unsigned long stats_timestamp; - /* The first is accessed under semaphore locking. - * The second is the clean one we return to iwconfig. - */ - struct iw_statistics local_iwstatistics; - struct iw_statistics iwstatistics; - - struct iw_spy_data spy_data; /* iwspy support */ - - struct iw_public_data wireless_data; - - int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */ - - struct islpci_acl acl; - - /* PCI bus allocation & configuration members */ - struct pci_dev *pdev; /* PCI structure information */ - char firmware[33]; - - void __iomem *device_base; /* ioremapped device base address */ - - /* consistent DMA region */ - void *driver_mem_address; /* base DMA address */ - dma_addr_t device_host_address; /* base DMA address (bus address) */ - dma_addr_t device_psm_buffer; /* host memory for PSM buffering (bus address) */ - - /* our network_device structure */ - struct net_device *ndev; - - /* device queue interface members */ - struct isl38xx_cb *control_block; /* device control block - (== driver_mem_address!) */ - - /* Each queue has three indexes: - * free/index_mgmt/data_rx/tx (called index, see below), - * driver_curr_frag, and device_curr_frag (in the control block) - * All indexes are ever-increasing, but interpreted modulo the - * device queue size when used. - * index <= device_curr_frag <= driver_curr_frag at all times - * For rx queues, [index, device_curr_frag) contains fragments - * that the interrupt processing needs to handle (owned by driver). - * [device_curr_frag, driver_curr_frag) is the free space in the - * rx queue, waiting for data (owned by device). The driver - * increments driver_curr_frag to indicate to the device that more - * buffers are available. - * If device_curr_frag == driver_curr_frag, no more rx buffers are - * available, and the rx DMA engine of the device is halted. - * For tx queues, [index, device_curr_frag) contains fragments - * where tx is done; they need to be freed (owned by driver). - * [device_curr_frag, driver_curr_frag) contains the frames - * that are being transferred (owned by device). The driver - * increments driver_curr_frag to indicate that more tx work - * needs to be done. - */ - u32 index_mgmt_rx; /* real index mgmt rx queue */ - u32 index_mgmt_tx; /* read index mgmt tx queue */ - u32 free_data_rx; /* free pointer data rx queue */ - u32 free_data_tx; /* free pointer data tx queue */ - u32 data_low_tx_full; /* full detected flag */ - - /* frame memory buffers for the device queues */ - struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE]; - struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE]; - struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE]; - struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE]; - dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE]; - dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE]; - - /* wait for a reset interrupt */ - wait_queue_head_t reset_done; - - /* used by islpci_mgt_transaction */ - struct mutex mgmt_lock; /* serialize access to mailbox and wqueue */ - struct islpci_mgmtframe *mgmt_received; /* mbox for incoming frame */ - wait_queue_head_t mgmt_wqueue; /* waitqueue for mbox */ - - /* state machine */ - islpci_state_t state; - int state_off; /* enumeration of off-state, if 0 then - * we're not in any off-state */ - - /* WPA stuff */ - int wpa; /* WPA mode enabled */ - struct list_head bss_wpa_list; - int num_bss_wpa; - struct mutex wpa_lock; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - - struct work_struct reset_task; - int reset_task_pending; -} islpci_private; - -static inline islpci_state_t -islpci_get_state(islpci_private *priv) -{ - /* lock */ - return priv->state; - /* unlock */ -} - -islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state); - -#define ISLPCI_TX_TIMEOUT (2*HZ) - -irqreturn_t islpci_interrupt(int, void *); - -int prism54_post_setup(islpci_private *, int); -int islpci_reset(islpci_private *, int); - -static inline void -islpci_trigger(islpci_private *priv) -{ - isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP, - priv->device_base); -} - -int islpci_free_memory(islpci_private *); -struct net_device *islpci_setup(struct pci_dev *); - -#define DRV_NAME "prism54" -#define DRV_VERSION "1.2" - -#endif /* _ISLPCI_DEV_H */ diff --git a/drivers/net/wireless/intersil/prism54/islpci_eth.c b/drivers/net/wireless/intersil/prism54/islpci_eth.c deleted file mode 100644 index 74dd65716afd..000000000000 --- a/drivers/net/wireless/intersil/prism54/islpci_eth.c +++ /dev/null @@ -1,489 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2002 Intersil Americas Inc. - * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - */ - -#include <linux/module.h> -#include <linux/gfp.h> - -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/if_arp.h> -#include <asm/byteorder.h> - -#include "prismcompat.h" -#include "isl_38xx.h" -#include "islpci_eth.h" -#include "islpci_mgt.h" -#include "oid_mgt.h" - -/****************************************************************************** - Network Interface functions -******************************************************************************/ -void -islpci_eth_cleanup_transmit(islpci_private *priv, - isl38xx_control_block *control_block) -{ - struct sk_buff *skb; - u32 index; - - /* compare the control block read pointer with the free pointer */ - while (priv->free_data_tx != - le32_to_cpu(control_block-> - device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) { - /* read the index of the first fragment to be freed */ - index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE; - - /* check for holes in the arrays caused by multi fragment frames - * searching for the last fragment of a frame */ - if (priv->pci_map_tx_address[index]) { - /* entry is the last fragment of a frame - * free the skb structure and unmap pci memory */ - skb = priv->data_low_tx[index]; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, - "cleanup skb %p skb->data %p skb->len %u truesize %u\n", - skb, skb->data, skb->len, skb->truesize); -#endif - - dma_unmap_single(&priv->pdev->dev, - priv->pci_map_tx_address[index], - skb->len, DMA_TO_DEVICE); - dev_kfree_skb_irq(skb); - skb = NULL; - } - /* increment the free data low queue pointer */ - priv->free_data_tx++; - } -} - -netdev_tx_t -islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) -{ - islpci_private *priv = netdev_priv(ndev); - isl38xx_control_block *cb = priv->control_block; - u32 index; - dma_addr_t pci_map_address; - int frame_size; - isl38xx_fragment *fragment; - int offset; - struct sk_buff *newskb; - int newskb_offset; - unsigned long flags; - unsigned char wds_mac[6]; - u32 curr_frag; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit\n"); -#endif - - /* lock the driver code */ - spin_lock_irqsave(&priv->slock, flags); - - /* check whether the destination queue has enough fragments for the frame */ - curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); - if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { - printk(KERN_ERR "%s: transmit device queue full when awake\n", - ndev->name); - netif_stop_queue(ndev); - - /* trigger the device */ - isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, - ISL38XX_DEV_INT_REG); - udelay(ISL38XX_WRITEIO_DELAY); - goto drop_free; - } - /* Check alignment and WDS frame formatting. The start of the packet should - * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes - * and add WDS address information */ - if (likely(((long) skb->data & 0x03) | init_wds)) { - /* get the number of bytes to add and re-align */ - offset = (4 - (long) skb->data) & 0x03; - offset += init_wds ? 6 : 0; - - /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset, - init_wds); -#endif - - /* align the buffer on 4-byte boundary */ - skb_reserve(skb, (4 - (long) skb->data) & 0x03); - if (init_wds) { - /* wds requires an additional address field of 6 bytes */ - skb_put(skb, 6); -#ifdef ISLPCI_ETH_DEBUG - printk("islpci_eth_transmit:wds_mac\n"); -#endif - memmove(skb->data + 6, src, skb->len); - skb_copy_to_linear_data(skb, wds_mac, 6); - } else { - memmove(skb->data, src, skb->len); - } - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "memmove %p %p %i\n", skb->data, - src, skb->len); -#endif - } else { - newskb = - dev_alloc_skb(init_wds ? skb->len + 6 : skb->len); - if (unlikely(newskb == NULL)) { - printk(KERN_ERR "%s: Cannot allocate skb\n", - ndev->name); - goto drop_free; - } - newskb_offset = (4 - (long) newskb->data) & 0x03; - - /* Check if newskb->data is aligned */ - if (newskb_offset) - skb_reserve(newskb, newskb_offset); - - skb_put(newskb, init_wds ? skb->len + 6 : skb->len); - if (init_wds) { - skb_copy_from_linear_data(skb, - newskb->data + 6, - skb->len); - skb_copy_to_linear_data(newskb, wds_mac, 6); -#ifdef ISLPCI_ETH_DEBUG - printk("islpci_eth_transmit:wds_mac\n"); -#endif - } else - skb_copy_from_linear_data(skb, newskb->data, - skb->len); - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n", - newskb->data, skb->data, skb->len, init_wds); -#endif - - newskb->dev = skb->dev; - dev_kfree_skb_irq(skb); - skb = newskb; - } - } - /* display the buffer contents for debugging */ -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data); - display_buffer((char *) skb->data, skb->len); -#endif - - /* map the skb buffer to pci memory for DMA operation */ - pci_map_address = dma_map_single(&priv->pdev->dev, (void *)skb->data, - skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(&priv->pdev->dev, pci_map_address)) { - printk(KERN_WARNING "%s: cannot map buffer to PCI\n", - ndev->name); - goto drop_free; - } - /* Place the fragment in the control block structure. */ - index = curr_frag % ISL38XX_CB_TX_QSIZE; - fragment = &cb->tx_data_low[index]; - - priv->pci_map_tx_address[index] = pci_map_address; - /* store the skb address for future freeing */ - priv->data_low_tx[index] = skb; - /* set the proper fragment start address and size information */ - frame_size = skb->len; - fragment->size = cpu_to_le16(frame_size); - fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ - fragment->address = cpu_to_le32(pci_map_address); - curr_frag++; - - /* The fragment address in the control block must have been - * written before announcing the frame buffer to device. */ - wmb(); - cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag); - - if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD - > ISL38XX_CB_TX_QSIZE) { - /* stop sends from upper layers */ - netif_stop_queue(ndev); - - /* set the full flag for the transmission queue */ - priv->data_low_tx_full = 1; - } - - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += skb->len; - - /* trigger the device */ - islpci_trigger(priv); - - /* unlock the driver code */ - spin_unlock_irqrestore(&priv->slock, flags); - - return NETDEV_TX_OK; - - drop_free: - ndev->stats.tx_dropped++; - spin_unlock_irqrestore(&priv->slock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -static inline int -islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb) -{ - /* The card reports full 802.11 packets but with a 20 bytes - * header and without the FCS. But there a is a bit that - * indicates if the packet is corrupted :-) */ - struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data; - - if (hdr->flags & 0x01) - /* This one is bad. Drop it ! */ - return -1; - if (priv->ndev->type == ARPHRD_IEEE80211_PRISM) { - struct avs_80211_1_header *avs; - /* extract the relevant data from the header */ - u32 clock = le32_to_cpu(hdr->clock); - u8 rate = hdr->rate; - u16 freq = le16_to_cpu(hdr->freq); - u8 rssi = hdr->rssi; - - skb_pull(*skb, sizeof (struct rfmon_header)); - - if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) { - struct sk_buff *newskb = skb_copy_expand(*skb, - sizeof (struct - avs_80211_1_header), - 0, GFP_ATOMIC); - if (newskb) { - dev_kfree_skb_irq(*skb); - *skb = newskb; - } else - return -1; - /* This behavior is not very subtile... */ - } - - /* make room for the new header and fill it. */ - avs = skb_push(*skb, sizeof(struct avs_80211_1_header)); - - avs->version = cpu_to_be32(P80211CAPTURE_VERSION); - avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header)); - avs->mactime = cpu_to_be64(clock); - avs->hosttime = cpu_to_be64(jiffies); - avs->phytype = cpu_to_be32(6); /*OFDM: 6 for (g), 8 for (a) */ - avs->channel = cpu_to_be32(channel_of_freq(freq)); - avs->datarate = cpu_to_be32(rate * 5); - avs->antenna = cpu_to_be32(0); /*unknown */ - avs->priority = cpu_to_be32(0); /*unknown */ - avs->ssi_type = cpu_to_be32(3); /*2: dBm, 3: raw RSSI */ - avs->ssi_signal = cpu_to_be32(rssi & 0x7f); - avs->ssi_noise = cpu_to_be32(priv->local_iwstatistics.qual.noise); /*better than 'undefined', I assume */ - avs->preamble = cpu_to_be32(0); /*unknown */ - avs->encoding = cpu_to_be32(0); /*unknown */ - } else - skb_pull(*skb, sizeof (struct rfmon_header)); - - (*skb)->protocol = htons(ETH_P_802_2); - skb_reset_mac_header(*skb); - (*skb)->pkt_type = PACKET_OTHERHOST; - - return 0; -} - -int -islpci_eth_receive(islpci_private *priv) -{ - struct net_device *ndev = priv->ndev; - isl38xx_control_block *control_block = priv->control_block; - struct sk_buff *skb; - u16 size; - u32 index, offset; - unsigned char *src; - int discard = 0; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive\n"); -#endif - - /* the device has written an Ethernet frame in the data area - * of the sk_buff without updating the structure, do it now */ - index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE; - size = le16_to_cpu(control_block->rx_data_low[index].size); - skb = priv->data_low_rx[index]; - offset = ((unsigned long) - le32_to_cpu(control_block->rx_data_low[index].address) - - (unsigned long) skb->data) & 3; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, - "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n", - control_block->rx_data_low[priv->free_data_rx].address, skb->data, - skb->len, offset, skb->truesize); -#endif - - /* delete the streaming DMA mapping before processing the skb */ - dma_unmap_single(&priv->pdev->dev, priv->pci_map_rx_address[index], - MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); - - /* update the skb structure and align the buffer */ - skb_put(skb, size); - if (offset) { - /* shift the buffer allocation offset bytes to get the right frame */ - skb_pull(skb, 2); - skb_put(skb, 2); - } -#if VERBOSE > SHOW_ERROR_MESSAGES - /* display the buffer contents for debugging */ - DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); - display_buffer((char *) skb->data, skb->len); -#endif - - /* check whether WDS is enabled and whether the data frame is a WDS frame */ - - if (init_wds) { - /* WDS enabled, check for the wds address on the first 6 bytes of the buffer */ - src = skb->data + 6; - memmove(skb->data, src, skb->len - 6); - skb_trim(skb, skb->len - 6); - } -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb); - DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len); - - /* display the buffer contents for debugging */ - DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); - display_buffer((char *) skb->data, skb->len); -#endif - /* take care of monitor mode and spy monitoring. */ - if (unlikely(priv->iw_mode == IW_MODE_MONITOR)) { - skb->dev = ndev; - discard = islpci_monitor_rx(priv, &skb); - } else { - if (unlikely(skb->data[2 * ETH_ALEN] == 0)) { - /* The packet has a rx_annex. Read it for spy monitoring, Then - * remove it, while keeping the 2 leading MAC addr. - */ - struct iw_quality wstats; - struct rx_annex_header *annex = - (struct rx_annex_header *) skb->data; - wstats.level = annex->rfmon.rssi; - /* The noise value can be a bit outdated if nobody's - * reading wireless stats... */ - wstats.noise = priv->local_iwstatistics.qual.noise; - wstats.qual = wstats.level - wstats.noise; - wstats.updated = 0x07; - /* Update spy records */ - wireless_spy_update(ndev, annex->addr2, &wstats); - - skb_copy_from_linear_data(skb, - (skb->data + - sizeof(struct rfmon_header)), - 2 * ETH_ALEN); - skb_pull(skb, sizeof (struct rfmon_header)); - } - skb->protocol = eth_type_trans(skb, ndev); - } - skb->ip_summed = CHECKSUM_NONE; - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += size; - - /* deliver the skb to the network layer */ -#ifdef ISLPCI_ETH_DEBUG - printk - ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", - skb->data[0], skb->data[1], skb->data[2], skb->data[3], - skb->data[4], skb->data[5]); -#endif - if (unlikely(discard)) { - dev_kfree_skb_irq(skb); - skb = NULL; - } else - netif_rx(skb); - - /* increment the read index for the rx data low queue */ - priv->free_data_rx++; - - /* add one or more sk_buff structures */ - while (index = - le32_to_cpu(control_block-> - driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]), - index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) { - /* allocate an sk_buff for received data frames storage - * include any required allignment operations */ - skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2); - if (unlikely(skb == NULL)) { - /* error allocating an sk_buff structure elements */ - DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb\n"); - break; - } - skb_reserve(skb, (4 - (long) skb->data) & 0x03); - /* store the new skb structure pointer */ - index = index % ISL38XX_CB_RX_QSIZE; - priv->data_low_rx[index] = skb; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, - "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n", - skb, skb->data, skb->len, index, skb->truesize); -#endif - - /* set the streaming DMA mapping for proper PCI bus operation */ - priv->pci_map_rx_address[index] = - dma_map_single(&priv->pdev->dev, (void *)skb->data, - MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); - if (dma_mapping_error(&priv->pdev->dev, priv->pci_map_rx_address[index])) { - /* error mapping the buffer to device accessible memory address */ - DEBUG(SHOW_ERROR_MESSAGES, - "Error mapping DMA address\n"); - - /* free the skbuf structure before aborting */ - dev_kfree_skb_irq(skb); - skb = NULL; - break; - } - /* update the fragment address */ - control_block->rx_data_low[index].address = - cpu_to_le32((u32)priv->pci_map_rx_address[index]); - wmb(); - - /* increment the driver read pointer */ - le32_add_cpu(&control_block-> - driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1); - } - - /* trigger the device */ - islpci_trigger(priv); - - return 0; -} - -void -islpci_do_reset_and_wake(struct work_struct *work) -{ - islpci_private *priv = container_of(work, islpci_private, reset_task); - - islpci_reset(priv, 1); - priv->reset_task_pending = 0; - smp_wmb(); - netif_wake_queue(priv->ndev); -} - -void -islpci_eth_tx_timeout(struct net_device *ndev, unsigned int txqueue) -{ - islpci_private *priv = netdev_priv(ndev); - - /* increment the transmit error counter */ - ndev->stats.tx_errors++; - - if (!priv->reset_task_pending) { - printk(KERN_WARNING - "%s: tx_timeout, scheduling reset", ndev->name); - netif_stop_queue(ndev); - priv->reset_task_pending = 1; - schedule_work(&priv->reset_task); - } else { - printk(KERN_WARNING - "%s: tx_timeout, waiting for reset", ndev->name); - } -} diff --git a/drivers/net/wireless/intersil/prism54/islpci_eth.h b/drivers/net/wireless/intersil/prism54/islpci_eth.h deleted file mode 100644 index e433ccdc526b..000000000000 --- a/drivers/net/wireless/intersil/prism54/islpci_eth.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2002 Intersil Americas Inc. - */ - -#ifndef _ISLPCI_ETH_H -#define _ISLPCI_ETH_H - -#include "isl_38xx.h" -#include "islpci_dev.h" - -struct rfmon_header { - __le16 unk0; /* = 0x0000 */ - __le16 length; /* = 0x1400 */ - __le32 clock; /* 1MHz clock */ - u8 flags; - u8 unk1; - u8 rate; - u8 unk2; - __le16 freq; - __le16 unk3; - u8 rssi; - u8 padding[3]; -} __packed; - -struct rx_annex_header { - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - struct rfmon_header rfmon; -} __packed; - -/* wlan-ng (and hopefully others) AVS header, version one. Fields in - * network byte order. */ -#define P80211CAPTURE_VERSION 0x80211001 - -struct avs_80211_1_header { - __be32 version; - __be32 length; - __be64 mactime; - __be64 hosttime; - __be32 phytype; - __be32 channel; - __be32 datarate; - __be32 antenna; - __be32 priority; - __be32 ssi_type; - __be32 ssi_signal; - __be32 ssi_noise; - __be32 preamble; - __be32 encoding; -}; - -void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); -netdev_tx_t islpci_eth_transmit(struct sk_buff *, struct net_device *); -int islpci_eth_receive(islpci_private *); -void islpci_eth_tx_timeout(struct net_device *, unsigned int txqueue); -void islpci_do_reset_and_wake(struct work_struct *); - -#endif /* _ISL_GEN_H */ diff --git a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c deleted file mode 100644 index 31a1e61326ff..000000000000 --- a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c +++ /dev/null @@ -1,316 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2002 Intersil Americas Inc. - * Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> - */ - -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/init.h> /* For __init, __exit */ -#include <linux/dma-mapping.h> - -#include "prismcompat.h" -#include "islpci_dev.h" -#include "islpci_mgt.h" /* for pc_debug */ -#include "isl_oid.h" - -MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>"); -MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter"); -MODULE_LICENSE("GPL"); - -static int init_pcitm = 0; -module_param(init_pcitm, int, 0); - -/* In this order: vendor, device, subvendor, subdevice, class, class_mask, - * driver_data - * If you have an update for this please contact prism54-devel@prism54.org - * The latest list can be found at http://wireless.wiki.kernel.org/en/users/Drivers/p54 - */ -static const struct pci_device_id prism54_id_tbl[] = { - /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ - { - 0x1260, 0x3890, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 - }, - - /* 3COM 3CRWE154G72 Wireless LAN adapter */ - { - PCI_VDEVICE(3COM, 0x6001), 0 - }, - - /* Intersil PRISM Indigo Wireless LAN adapter */ - { - 0x1260, 0x3877, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 - }, - - /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ - { - 0x1260, 0x3886, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 - }, - - /* End of list */ - {0,0,0,0,0,0,0} -}; - -/* register the device with the Hotplug facilities of the kernel */ -MODULE_DEVICE_TABLE(pci, prism54_id_tbl); - -static int prism54_probe(struct pci_dev *, const struct pci_device_id *); -static void prism54_remove(struct pci_dev *); -static int __maybe_unused prism54_suspend(struct device *); -static int __maybe_unused prism54_resume(struct device *); - -static SIMPLE_DEV_PM_OPS(prism54_pm_ops, prism54_suspend, prism54_resume); - -static struct pci_driver prism54_driver = { - .name = DRV_NAME, - .id_table = prism54_id_tbl, - .probe = prism54_probe, - .remove = prism54_remove, - .driver.pm = &prism54_pm_ops, -}; - -/****************************************************************************** - Module initialization functions -******************************************************************************/ - -static int -prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct net_device *ndev; - u8 latency_tmr; - u32 mem_addr; - islpci_private *priv; - int rvalue; - - /* Enable the pci device */ - if (pci_enable_device(pdev)) { - printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); - return -ENODEV; - } - - /* check whether the latency timer is set correctly */ - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr); -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr); -#endif - if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) { - /* set the latency timer */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, - PCIDEVICE_LATENCY_TIMER_VAL); - } - - /* enable PCI DMA */ - if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { - printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); - goto do_pci_disable_device; - } - - /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT) - * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT) - * The RETRY_TIMEOUT is used to set the number of retries that the core, as a - * Master, will perform before abandoning a cycle. The default value for - * RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new - * devices. A write of zero to the RETRY_TIMEOUT register disables this - * function to allow use with any non-compliant legacy devices that may - * execute more retries. - * - * Writing zero to both these two registers will disable both timeouts and - * *can* solve problems caused by devices that are slow to respond. - * Make this configurable - MSW - */ - if ( init_pcitm >= 0 ) { - pci_write_config_byte(pdev, 0x40, (u8)init_pcitm); - pci_write_config_byte(pdev, 0x41, (u8)init_pcitm); - } else { - printk(KERN_INFO "PCI TRDY/RETRY unchanged\n"); - } - - /* request the pci device I/O regions */ - rvalue = pci_request_regions(pdev, DRV_NAME); - if (rvalue) { - printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n", - DRV_NAME, rvalue); - goto do_pci_disable_device; - } - - /* check if the memory window is indeed set */ - rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr); - if (rvalue || !mem_addr) { - printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n", - DRV_NAME); - goto do_pci_release_regions; - } - - /* enable PCI bus-mastering */ - DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME); - pci_set_master(pdev); - - /* enable MWI */ - pci_try_set_mwi(pdev); - - /* setup the network device interface and its structure */ - if (!(ndev = islpci_setup(pdev))) { - /* error configuring the driver as a network device */ - printk(KERN_ERR "%s: could not configure network device\n", - DRV_NAME); - goto do_pci_clear_mwi; - } - - priv = netdev_priv(ndev); - islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */ - - /* card is in unknown state yet, might have some interrupts pending */ - isl38xx_disable_interrupts(priv->device_base); - - /* request for the interrupt before uploading the firmware */ - rvalue = request_irq(pdev->irq, islpci_interrupt, - IRQF_SHARED, ndev->name, priv); - - if (rvalue) { - /* error, could not hook the handler to the irq */ - printk(KERN_ERR "%s: could not install IRQ handler\n", - ndev->name); - goto do_unregister_netdev; - } - - /* firmware upload is triggered in islpci_open */ - - return 0; - - do_unregister_netdev: - unregister_netdev(ndev); - islpci_free_memory(priv); - free_netdev(ndev); - priv = NULL; - do_pci_clear_mwi: - pci_clear_mwi(pdev); - do_pci_release_regions: - pci_release_regions(pdev); - do_pci_disable_device: - pci_disable_device(pdev); - return -EIO; -} - -/* set by cleanup_module */ -static volatile int __in_cleanup_module = 0; - -/* this one removes one(!!) instance only */ -static void -prism54_remove(struct pci_dev *pdev) -{ - struct net_device *ndev = pci_get_drvdata(pdev); - islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; - BUG_ON(!priv); - - if (!__in_cleanup_module) { - printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name); - islpci_set_state(priv, PRV_STATE_OFF); - } - - printk(KERN_DEBUG "%s: removing device\n", ndev->name); - - unregister_netdev(ndev); - - /* free the interrupt request */ - - if (islpci_get_state(priv) != PRV_STATE_OFF) { - isl38xx_disable_interrupts(priv->device_base); - islpci_set_state(priv, PRV_STATE_OFF); - /* This bellow causes a lockup at rmmod time. It might be - * because some interrupts still linger after rmmod time, - * see bug #17 */ - /* pci_set_power_state(pdev, 3);*/ /* try to power-off */ - } - - free_irq(pdev->irq, priv); - - /* free the PCI memory and unmap the remapped page */ - islpci_free_memory(priv); - - free_netdev(ndev); - priv = NULL; - - pci_clear_mwi(pdev); - - pci_release_regions(pdev); - - pci_disable_device(pdev); -} - -static int __maybe_unused -prism54_suspend(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; - BUG_ON(!priv); - - /* tell the device not to trigger interrupts for now... */ - isl38xx_disable_interrupts(priv->device_base); - - /* from now on assume the hardware was already powered down - and don't touch it anymore */ - islpci_set_state(priv, PRV_STATE_OFF); - - netif_stop_queue(ndev); - netif_device_detach(ndev); - - return 0; -} - -static int __maybe_unused -prism54_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; - - BUG_ON(!priv); - - printk(KERN_NOTICE "%s: got resume request\n", ndev->name); - - /* alright let's go into the PREBOOT state */ - islpci_reset(priv, 1); - - netif_device_attach(ndev); - netif_start_queue(ndev); - - return 0; -} - -static int __init -prism54_module_init(void) -{ - printk(KERN_INFO "Loaded %s driver, version %s\n", - DRV_NAME, DRV_VERSION); - - __bug_on_wrong_struct_sizes (); - - return pci_register_driver(&prism54_driver); -} - -/* by the time prism54_module_exit() terminates, as a postcondition - * all instances will have been destroyed by calls to - * prism54_remove() */ -static void __exit -prism54_module_exit(void) -{ - __in_cleanup_module = 1; - - pci_unregister_driver(&prism54_driver); - - printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME); - - __in_cleanup_module = 0; -} - -/* register entry points */ -module_init(prism54_module_init); -module_exit(prism54_module_exit); -/* EOF */ diff --git a/drivers/net/wireless/intersil/prism54/islpci_mgt.c b/drivers/net/wireless/intersil/prism54/islpci_mgt.c deleted file mode 100644 index 0c7fb76c7d1c..000000000000 --- a/drivers/net/wireless/intersil/prism54/islpci_mgt.c +++ /dev/null @@ -1,491 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2002 Intersil Americas Inc. - * Copyright 2004 Jens Maurer <Jens.Maurer@gmx.net> - */ - -#include <linux/netdevice.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/slab.h> - -#include <asm/io.h> -#include <linux/if_arp.h> - -#include "prismcompat.h" -#include "isl_38xx.h" -#include "islpci_mgt.h" -#include "isl_oid.h" /* additional types and defs for isl38xx fw */ -#include "isl_ioctl.h" - -#include <net/iw_handler.h> - -/****************************************************************************** - Global variable definition section -******************************************************************************/ -int pc_debug = VERBOSE; -module_param(pc_debug, int, 0); - -/****************************************************************************** - Driver general functions -******************************************************************************/ -#if VERBOSE > SHOW_ERROR_MESSAGES -void -display_buffer(char *buffer, int length) -{ - if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0) - return; - - while (length > 0) { - printk("[%02x]", *buffer & 255); - length--; - buffer++; - } - - printk("\n"); -} -#endif - -/***************************************************************************** - Queue handling for management frames -******************************************************************************/ - -/* - * Helper function to create a PIMFOR management frame header. - */ -static void -pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h) -{ - h->version = PIMFOR_VERSION; - h->operation = operation; - h->device_id = PIMFOR_DEV_ID_MHLI_MIB; - h->flags = 0; - h->oid = cpu_to_be32(oid); - h->length = cpu_to_be32(length); -} - -/* - * Helper function to analyze a PIMFOR management frame header. - */ -static pimfor_header_t * -pimfor_decode_header(void *data, int len) -{ - pimfor_header_t *h = data; - - while ((void *) h < data + len) { - if (h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) { - le32_to_cpus(&h->oid); - le32_to_cpus(&h->length); - } else { - be32_to_cpus(&h->oid); - be32_to_cpus(&h->length); - } - if (h->oid != OID_INL_TUNNEL) - return h; - h++; - } - return NULL; -} - -/* - * Fill the receive queue for management frames with fresh buffers. - */ -int -islpci_mgmt_rx_fill(struct net_device *ndev) -{ - islpci_private *priv = netdev_priv(ndev); - isl38xx_control_block *cb = /* volatile not needed */ - (isl38xx_control_block *) priv->control_block; - u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]); - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill\n"); -#endif - - while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) { - u32 index = curr % ISL38XX_CB_MGMT_QSIZE; - struct islpci_membuf *buf = &priv->mgmt_rx[index]; - isl38xx_fragment *frag = &cb->rx_data_mgmt[index]; - - if (buf->mem == NULL) { - buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC); - if (!buf->mem) - return -ENOMEM; - buf->size = MGMT_FRAME_SIZE; - } - if (buf->pci_addr == 0) { - buf->pci_addr = dma_map_single(&priv->pdev->dev, - buf->mem, - MGMT_FRAME_SIZE, - DMA_FROM_DEVICE); - if (dma_mapping_error(&priv->pdev->dev, buf->pci_addr)) { - printk(KERN_WARNING - "Failed to make memory DMA'able.\n"); - return -ENOMEM; - } - } - - /* be safe: always reset control block information */ - frag->size = cpu_to_le16(MGMT_FRAME_SIZE); - frag->flags = 0; - frag->address = cpu_to_le32(buf->pci_addr); - curr++; - - /* The fragment address in the control block must have - * been written before announcing the frame buffer to - * device */ - wmb(); - cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(curr); - } - return 0; -} - -/* - * Create and transmit a management frame using "operation" and "oid", - * with arguments data/length. - * We either return an error and free the frame, or we return 0 and - * islpci_mgt_cleanup_transmit() frees the frame in the tx-done - * interrupt. - */ -static int -islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, - void *data, int length) -{ - islpci_private *priv = netdev_priv(ndev); - isl38xx_control_block *cb = - (isl38xx_control_block *) priv->control_block; - void *p; - int err = -EINVAL; - unsigned long flags; - isl38xx_fragment *frag; - struct islpci_membuf buf; - u32 curr_frag; - int index; - int frag_len = length + PIMFOR_HEADER_SIZE; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n"); -#endif - - if (frag_len > MGMT_FRAME_SIZE) { - printk(KERN_DEBUG "%s: mgmt frame too large %d\n", - ndev->name, frag_len); - goto error; - } - - err = -ENOMEM; - p = buf.mem = kmalloc(frag_len, GFP_KERNEL); - if (!buf.mem) - goto error; - - buf.size = frag_len; - - /* create the header directly in the fragment data area */ - pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p); - p += PIMFOR_HEADER_SIZE; - - if (data) - memcpy(p, data, length); - else - memset(p, 0, length); - -#if VERBOSE > SHOW_ERROR_MESSAGES - { - pimfor_header_t *h = buf.mem; - DEBUG(SHOW_PIMFOR_FRAMES, - "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x\n", - h->operation, oid, h->device_id, h->flags, length); - - /* display the buffer contents for debugging */ - display_buffer((char *) h, sizeof (pimfor_header_t)); - display_buffer(p, length); - } -#endif - - err = -ENOMEM; - buf.pci_addr = dma_map_single(&priv->pdev->dev, buf.mem, frag_len, - DMA_TO_DEVICE); - if (dma_mapping_error(&priv->pdev->dev, buf.pci_addr)) { - printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", - ndev->name); - goto error_free; - } - - /* Protect the control block modifications against interrupts. */ - spin_lock_irqsave(&priv->slock, flags); - curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]); - if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) { - printk(KERN_WARNING "%s: mgmt tx queue is still full\n", - ndev->name); - goto error_unlock; - } - - /* commit the frame to the tx device queue */ - index = curr_frag % ISL38XX_CB_MGMT_QSIZE; - priv->mgmt_tx[index] = buf; - frag = &cb->tx_data_mgmt[index]; - frag->size = cpu_to_le16(frag_len); - frag->flags = 0; /* for any other than the last fragment, set to 1 */ - frag->address = cpu_to_le32(buf.pci_addr); - - /* The fragment address in the control block must have - * been written before announcing the frame buffer to - * device */ - wmb(); - cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1); - spin_unlock_irqrestore(&priv->slock, flags); - - /* trigger the device */ - islpci_trigger(priv); - return 0; - - error_unlock: - spin_unlock_irqrestore(&priv->slock, flags); - error_free: - kfree(buf.mem); - error: - return err; -} - -/* - * Receive a management frame from the device. - * This can be an arbitrary number of traps, and at most one response - * frame for a previous request sent via islpci_mgt_transmit(). - */ -int -islpci_mgt_receive(struct net_device *ndev) -{ - islpci_private *priv = netdev_priv(ndev); - isl38xx_control_block *cb = - (isl38xx_control_block *) priv->control_block; - u32 curr_frag; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive\n"); -#endif - - /* Only once per interrupt, determine fragment range to - * process. This avoids an endless loop (i.e. lockup) if - * frames come in faster than we can process them. */ - curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]); - barrier(); - - for (; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) { - pimfor_header_t *header; - u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE; - struct islpci_membuf *buf = &priv->mgmt_rx[index]; - u16 frag_len; - int size; - struct islpci_mgmtframe *frame; - - /* I have no idea (and no documentation) if flags != 0 - * is possible. Drop the frame, reuse the buffer. */ - if (le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) { - printk(KERN_WARNING "%s: unknown flags 0x%04x\n", - ndev->name, - le16_to_cpu(cb->rx_data_mgmt[index].flags)); - continue; - } - - /* The device only returns the size of the header(s) here. */ - frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size); - - /* - * We appear to have no way to tell the device the - * size of a receive buffer. Thus, if this check - * triggers, we likely have kernel heap corruption. */ - if (frag_len > MGMT_FRAME_SIZE) { - printk(KERN_WARNING - "%s: Bogus packet size of %d (%#x).\n", - ndev->name, frag_len, frag_len); - frag_len = MGMT_FRAME_SIZE; - } - - /* Ensure the results of device DMA are visible to the CPU. */ - dma_sync_single_for_cpu(&priv->pdev->dev, buf->pci_addr, - buf->size, DMA_FROM_DEVICE); - - /* Perform endianess conversion for PIMFOR header in-place. */ - header = pimfor_decode_header(buf->mem, frag_len); - if (!header) { - printk(KERN_WARNING "%s: no PIMFOR header found\n", - ndev->name); - continue; - } - - /* The device ID from the PIMFOR packet received from - * the MVC is always 0. We forward a sensible device_id. - * Not that anyone upstream would care... */ - header->device_id = priv->ndev->ifindex; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_PIMFOR_FRAMES, - "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x\n", - header->operation, header->oid, header->device_id, - header->flags, header->length); - - /* display the buffer contents for debugging */ - display_buffer((char *) header, PIMFOR_HEADER_SIZE); - display_buffer((char *) header + PIMFOR_HEADER_SIZE, - header->length); -#endif - - /* nobody sends these */ - if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) { - printk(KERN_DEBUG - "%s: errant PIMFOR application frame\n", - ndev->name); - continue; - } - - /* Determine frame size, skipping OID_INL_TUNNEL headers. */ - size = PIMFOR_HEADER_SIZE + header->length; - frame = kmalloc(sizeof(struct islpci_mgmtframe) + size, - GFP_ATOMIC); - if (!frame) - continue; - - frame->ndev = ndev; - memcpy(&frame->buf, header, size); - frame->header = (pimfor_header_t *) frame->buf; - frame->data = frame->buf + PIMFOR_HEADER_SIZE; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_PIMFOR_FRAMES, - "frame: header: %p, data: %p, size: %d\n", - frame->header, frame->data, size); -#endif - - if (header->operation == PIMFOR_OP_TRAP) { -#if VERBOSE > SHOW_ERROR_MESSAGES - printk(KERN_DEBUG - "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n", - header->oid, header->device_id, header->flags, - header->length); -#endif - - /* Create work to handle trap out of interrupt - * context. */ - INIT_WORK(&frame->ws, prism54_process_trap); - schedule_work(&frame->ws); - - } else { - /* Signal the one waiting process that a response - * has been received. */ - if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) { - printk(KERN_WARNING - "%s: mgmt response not collected\n", - ndev->name); - kfree(frame); - } -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_TRACING, "Wake up Mgmt Queue\n"); -#endif - wake_up(&priv->mgmt_wqueue); - } - - } - - return 0; -} - -/* - * Cleanup the transmit queue by freeing all frames handled by the device. - */ -void -islpci_mgt_cleanup_transmit(struct net_device *ndev) -{ - islpci_private *priv = netdev_priv(ndev); - isl38xx_control_block *cb = /* volatile not needed */ - (isl38xx_control_block *) priv->control_block; - u32 curr_frag; - -#if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n"); -#endif - - /* Only once per cleanup, determine fragment range to - * process. This avoids an endless loop (i.e. lockup) if - * the device became confused, incrementing device_curr_frag - * rapidly. */ - curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]); - barrier(); - - for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) { - int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE; - struct islpci_membuf *buf = &priv->mgmt_tx[index]; - dma_unmap_single(&priv->pdev->dev, buf->pci_addr, buf->size, - DMA_TO_DEVICE); - buf->pci_addr = 0; - kfree(buf->mem); - buf->mem = NULL; - buf->size = 0; - } -} - -/* - * Perform one request-response transaction to the device. - */ -int -islpci_mgt_transaction(struct net_device *ndev, - int operation, unsigned long oid, - void *senddata, int sendlen, - struct islpci_mgmtframe **recvframe) -{ - islpci_private *priv = netdev_priv(ndev); - const long wait_cycle_jiffies = msecs_to_jiffies(ISL38XX_WAIT_CYCLE * 10); - long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; - int err; - DEFINE_WAIT(wait); - - *recvframe = NULL; - - if (mutex_lock_interruptible(&priv->mgmt_lock)) - return -ERESTARTSYS; - - prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE); - err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen); - if (err) - goto out; - - err = -ETIMEDOUT; - while (timeout_left > 0) { - int timeleft; - struct islpci_mgmtframe *frame; - - timeleft = schedule_timeout_uninterruptible(wait_cycle_jiffies); - frame = xchg(&priv->mgmt_received, NULL); - if (frame) { - if (frame->header->oid == oid) { - *recvframe = frame; - err = 0; - goto out; - } else { - printk(KERN_DEBUG - "%s: expecting oid 0x%x, received 0x%x.\n", - ndev->name, (unsigned int) oid, - frame->header->oid); - kfree(frame); - frame = NULL; - } - } - if (timeleft == 0) { - printk(KERN_DEBUG - "%s: timeout waiting for mgmt response %lu, " - "triggering device\n", - ndev->name, timeout_left); - islpci_trigger(priv); - } - timeout_left += timeleft - wait_cycle_jiffies; - } - printk(KERN_WARNING "%s: timeout waiting for mgmt response\n", - ndev->name); - - /* TODO: we should reset the device here */ - out: - finish_wait(&priv->mgmt_wqueue, &wait); - mutex_unlock(&priv->mgmt_lock); - return err; -} - diff --git a/drivers/net/wireless/intersil/prism54/islpci_mgt.h b/drivers/net/wireless/intersil/prism54/islpci_mgt.h deleted file mode 100644 index 1f87d0aea60c..000000000000 --- a/drivers/net/wireless/intersil/prism54/islpci_mgt.h +++ /dev/null @@ -1,126 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2002 Intersil Americas Inc. - * Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> - */ - -#ifndef _ISLPCI_MGT_H -#define _ISLPCI_MGT_H - -#include <linux/wireless.h> -#include <linux/skbuff.h> -#include <linux/slab.h> - -/* - * Function definitions - */ - -#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0) -#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args) - -extern int pc_debug; -#define init_wds 0 /* help compiler optimize away dead code */ - - -/* General driver definitions */ -#define PCIDEVICE_LATENCY_TIMER_MIN 0x40 -#define PCIDEVICE_LATENCY_TIMER_VAL 0x50 - -/* Debugging verbose definitions */ -#define SHOW_NOTHING 0x00 /* overrules everything */ -#define SHOW_ANYTHING 0xFF -#define SHOW_ERROR_MESSAGES 0x01 -#define SHOW_TRAPS 0x02 -#define SHOW_FUNCTION_CALLS 0x04 -#define SHOW_TRACING 0x08 -#define SHOW_QUEUE_INDEXES 0x10 -#define SHOW_PIMFOR_FRAMES 0x20 -#define SHOW_BUFFER_CONTENTS 0x40 -#define VERBOSE 0x01 - -/* Default card definitions */ -#define CARD_DEFAULT_CHANNEL 6 -#define CARD_DEFAULT_MODE INL_MODE_CLIENT -#define CARD_DEFAULT_IW_MODE IW_MODE_INFRA -#define CARD_DEFAULT_BSSTYPE DOT11_BSSTYPE_INFRA -#define CARD_DEFAULT_CLIENT_SSID "" -#define CARD_DEFAULT_AP_SSID "default" -#define CARD_DEFAULT_KEY1 "default_key_1" -#define CARD_DEFAULT_KEY2 "default_key_2" -#define CARD_DEFAULT_KEY3 "default_key_3" -#define CARD_DEFAULT_KEY4 "default_key_4" -#define CARD_DEFAULT_WEP 0 -#define CARD_DEFAULT_FILTER 0 -#define CARD_DEFAULT_WDS 0 -#define CARD_DEFAULT_AUTHEN DOT11_AUTH_OS -#define CARD_DEFAULT_DOT1X 0 -#define CARD_DEFAULT_MLME_MODE DOT11_MLME_AUTO -#define CARD_DEFAULT_CONFORMANCE OID_INL_CONFORMANCE_NONE -#define CARD_DEFAULT_PROFILE DOT11_PROFILE_MIXED_G_WIFI -#define CARD_DEFAULT_MAXFRAMEBURST DOT11_MAXFRAMEBURST_MIXED_SAFE - -/* PIMFOR package definitions */ -#define PIMFOR_ETHERTYPE 0x8828 -#define PIMFOR_HEADER_SIZE 12 -#define PIMFOR_VERSION 1 -#define PIMFOR_OP_GET 0 -#define PIMFOR_OP_SET 1 -#define PIMFOR_OP_RESPONSE 2 -#define PIMFOR_OP_ERROR 3 -#define PIMFOR_OP_TRAP 4 -#define PIMFOR_OP_RESERVED 5 /* till 255 */ -#define PIMFOR_DEV_ID_MHLI_MIB 0 -#define PIMFOR_FLAG_APPLIC_ORIGIN 0x01 -#define PIMFOR_FLAG_LITTLE_ENDIAN 0x02 - -void display_buffer(char *, int); - -/* - * Type definition section - * - * the structure defines only the header allowing copyless - * frame handling - */ -typedef struct { - u8 version; - u8 operation; - u32 oid; - u8 device_id; - u8 flags; - u32 length; -} __packed -pimfor_header_t; - -/* A received and interrupt-processed management frame, either for - * schedule_work(prism54_process_trap) or for priv->mgmt_received, - * processed by islpci_mgt_transaction(). */ -struct islpci_mgmtframe { - struct net_device *ndev; /* pointer to network device */ - pimfor_header_t *header; /* payload header, points into buf */ - void *data; /* payload ex header, points into buf */ - struct work_struct ws; /* argument for schedule_work() */ - char buf[]; /* fragment buffer */ -}; - -int -islpci_mgt_receive(struct net_device *ndev); - -int -islpci_mgmt_rx_fill(struct net_device *ndev); - -void -islpci_mgt_cleanup_transmit(struct net_device *ndev); - -int -islpci_mgt_transaction(struct net_device *ndev, - int operation, unsigned long oid, - void *senddata, int sendlen, - struct islpci_mgmtframe **recvframe); - -static inline void -islpci_mgt_release(struct islpci_mgmtframe *frame) -{ - kfree(frame); -} - -#endif /* _ISLPCI_MGT_H */ diff --git a/drivers/net/wireless/intersil/prism54/oid_mgt.c b/drivers/net/wireless/intersil/prism54/oid_mgt.c deleted file mode 100644 index 9fd307ca4b6d..000000000000 --- a/drivers/net/wireless/intersil/prism54/oid_mgt.c +++ /dev/null @@ -1,889 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2003,2004 Aurelien Alleaume <slts@free.fr> - */ - -#include <linux/kernel.h> -#include <linux/slab.h> - -#include "prismcompat.h" -#include "islpci_dev.h" -#include "islpci_mgt.h" -#include "isl_oid.h" -#include "oid_mgt.h" -#include "isl_ioctl.h" - -/* to convert between channel and freq */ -static const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, - 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; - -int -channel_of_freq(int f) -{ - int c = 0; - - if ((f >= 2412) && (f <= 2484)) { - while ((c < 14) && (f != frequency_list_bg[c])) - c++; - return (c >= 14) ? 0 : ++c; - } else if ((f >= (int) 5000) && (f <= (int) 6000)) { - return ( (f - 5000) / 5 ); - } else - return 0; -} - -#define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t} -#define OID_STRUCT_C(name,oid,s,t) OID_STRUCT(name,oid,s,t | OID_FLAG_CACHED) -#define OID_U32(name,oid) OID_STRUCT(name,oid,u32,OID_TYPE_U32) -#define OID_U32_C(name,oid) OID_STRUCT_C(name,oid,u32,OID_TYPE_U32) -#define OID_STRUCT_MLME(name,oid) OID_STRUCT(name,oid,struct obj_mlme,OID_TYPE_MLME) -#define OID_STRUCT_MLMEEX(name,oid) OID_STRUCT(name,oid,struct obj_mlmeex,OID_TYPE_MLMEEX) - -#define OID_UNKNOWN(name,oid) OID_STRUCT(name,oid,0,0) - -struct oid_t isl_oid[] = { - OID_STRUCT(GEN_OID_MACADDRESS, 0x00000000, u8[6], OID_TYPE_ADDR), - OID_U32(GEN_OID_LINKSTATE, 0x00000001), - OID_UNKNOWN(GEN_OID_WATCHDOG, 0x00000002), - OID_UNKNOWN(GEN_OID_MIBOP, 0x00000003), - OID_UNKNOWN(GEN_OID_OPTIONS, 0x00000004), - OID_UNKNOWN(GEN_OID_LEDCONFIG, 0x00000005), - - /* 802.11 */ - OID_U32_C(DOT11_OID_BSSTYPE, 0x10000000), - OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_RAW), - OID_STRUCT_C(DOT11_OID_SSID, 0x10000002, struct obj_ssid, - OID_TYPE_SSID), - OID_U32(DOT11_OID_STATE, 0x10000003), - OID_U32(DOT11_OID_AID, 0x10000004), - OID_STRUCT(DOT11_OID_COUNTRYSTRING, 0x10000005, u8[4], OID_TYPE_RAW), - OID_STRUCT_C(DOT11_OID_SSIDOVERRIDE, 0x10000006, struct obj_ssid, - OID_TYPE_SSID), - - OID_U32(DOT11_OID_MEDIUMLIMIT, 0x11000000), - OID_U32_C(DOT11_OID_BEACONPERIOD, 0x11000001), - OID_U32(DOT11_OID_DTIMPERIOD, 0x11000002), - OID_U32(DOT11_OID_ATIMWINDOW, 0x11000003), - OID_U32(DOT11_OID_LISTENINTERVAL, 0x11000004), - OID_U32(DOT11_OID_CFPPERIOD, 0x11000005), - OID_U32(DOT11_OID_CFPDURATION, 0x11000006), - - OID_U32_C(DOT11_OID_AUTHENABLE, 0x12000000), - OID_U32_C(DOT11_OID_PRIVACYINVOKED, 0x12000001), - OID_U32_C(DOT11_OID_EXUNENCRYPTED, 0x12000002), - OID_U32_C(DOT11_OID_DEFKEYID, 0x12000003), - [DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key), - OID_FLAG_CACHED | OID_TYPE_KEY}, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ - OID_UNKNOWN(DOT11_OID_STAKEY, 0x12000008), - OID_U32(DOT11_OID_REKEYTHRESHOLD, 0x12000009), - OID_UNKNOWN(DOT11_OID_STASC, 0x1200000a), - - OID_U32(DOT11_OID_PRIVTXREJECTED, 0x1a000000), - OID_U32(DOT11_OID_PRIVRXPLAIN, 0x1a000001), - OID_U32(DOT11_OID_PRIVRXFAILED, 0x1a000002), - OID_U32(DOT11_OID_PRIVRXNOKEY, 0x1a000003), - - OID_U32_C(DOT11_OID_RTSTHRESH, 0x13000000), - OID_U32_C(DOT11_OID_FRAGTHRESH, 0x13000001), - OID_U32_C(DOT11_OID_SHORTRETRIES, 0x13000002), - OID_U32_C(DOT11_OID_LONGRETRIES, 0x13000003), - OID_U32_C(DOT11_OID_MAXTXLIFETIME, 0x13000004), - OID_U32(DOT11_OID_MAXRXLIFETIME, 0x13000005), - OID_U32(DOT11_OID_AUTHRESPTIMEOUT, 0x13000006), - OID_U32(DOT11_OID_ASSOCRESPTIMEOUT, 0x13000007), - - OID_UNKNOWN(DOT11_OID_ALOFT_TABLE, 0x1d000000), - OID_UNKNOWN(DOT11_OID_ALOFT_CTRL_TABLE, 0x1d000001), - OID_UNKNOWN(DOT11_OID_ALOFT_RETREAT, 0x1d000002), - OID_UNKNOWN(DOT11_OID_ALOFT_PROGRESS, 0x1d000003), - OID_U32(DOT11_OID_ALOFT_FIXEDRATE, 0x1d000004), - OID_UNKNOWN(DOT11_OID_ALOFT_RSSIGRAPH, 0x1d000005), - OID_UNKNOWN(DOT11_OID_ALOFT_CONFIG, 0x1d000006), - - [DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0}, - OID_U32(DOT11_OID_MAXFRAMEBURST, 0x1b000008), - - OID_U32(DOT11_OID_PSM, 0x14000000), - OID_U32(DOT11_OID_CAMTIMEOUT, 0x14000001), - OID_U32(DOT11_OID_RECEIVEDTIMS, 0x14000002), - OID_U32(DOT11_OID_ROAMPREFERENCE, 0x14000003), - - OID_U32(DOT11_OID_BRIDGELOCAL, 0x15000000), - OID_U32(DOT11_OID_CLIENTS, 0x15000001), - OID_U32(DOT11_OID_CLIENTSASSOCIATED, 0x15000002), - [DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0}, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ - - OID_STRUCT(DOT11_OID_CLIENTFIND, 0x150007DB, u8[6], OID_TYPE_ADDR), - OID_STRUCT(DOT11_OID_WDSLINKADD, 0x150007DC, u8[6], OID_TYPE_ADDR), - OID_STRUCT(DOT11_OID_WDSLINKREMOVE, 0x150007DD, u8[6], OID_TYPE_ADDR), - OID_STRUCT(DOT11_OID_EAPAUTHSTA, 0x150007DE, u8[6], OID_TYPE_ADDR), - OID_STRUCT(DOT11_OID_EAPUNAUTHSTA, 0x150007DF, u8[6], OID_TYPE_ADDR), - OID_U32_C(DOT11_OID_DOT1XENABLE, 0x150007E0), - OID_UNKNOWN(DOT11_OID_MICFAILURE, 0x150007E1), - OID_UNKNOWN(DOT11_OID_REKEYINDICATE, 0x150007E2), - - OID_U32(DOT11_OID_MPDUTXSUCCESSFUL, 0x16000000), - OID_U32(DOT11_OID_MPDUTXONERETRY, 0x16000001), - OID_U32(DOT11_OID_MPDUTXMULTIPLERETRIES, 0x16000002), - OID_U32(DOT11_OID_MPDUTXFAILED, 0x16000003), - OID_U32(DOT11_OID_MPDURXSUCCESSFUL, 0x16000004), - OID_U32(DOT11_OID_MPDURXDUPS, 0x16000005), - OID_U32(DOT11_OID_RTSSUCCESSFUL, 0x16000006), - OID_U32(DOT11_OID_RTSFAILED, 0x16000007), - OID_U32(DOT11_OID_ACKFAILED, 0x16000008), - OID_U32(DOT11_OID_FRAMERECEIVES, 0x16000009), - OID_U32(DOT11_OID_FRAMEERRORS, 0x1600000A), - OID_U32(DOT11_OID_FRAMEABORTS, 0x1600000B), - OID_U32(DOT11_OID_FRAMEABORTSPHY, 0x1600000C), - - OID_U32(DOT11_OID_SLOTTIME, 0x17000000), - OID_U32(DOT11_OID_CWMIN, 0x17000001), - OID_U32(DOT11_OID_CWMAX, 0x17000002), - OID_U32(DOT11_OID_ACKWINDOW, 0x17000003), - OID_U32(DOT11_OID_ANTENNARX, 0x17000004), - OID_U32(DOT11_OID_ANTENNATX, 0x17000005), - OID_U32(DOT11_OID_ANTENNADIVERSITY, 0x17000006), - OID_U32_C(DOT11_OID_CHANNEL, 0x17000007), - OID_U32_C(DOT11_OID_EDTHRESHOLD, 0x17000008), - OID_U32(DOT11_OID_PREAMBLESETTINGS, 0x17000009), - OID_STRUCT(DOT11_OID_RATES, 0x1700000A, u8[IWMAX_BITRATES + 1], - OID_TYPE_RAW), - OID_U32(DOT11_OID_CCAMODESUPPORTED, 0x1700000B), - OID_U32(DOT11_OID_CCAMODE, 0x1700000C), - OID_UNKNOWN(DOT11_OID_RSSIVECTOR, 0x1700000D), - OID_UNKNOWN(DOT11_OID_OUTPUTPOWERTABLE, 0x1700000E), - OID_U32(DOT11_OID_OUTPUTPOWER, 0x1700000F), - OID_STRUCT(DOT11_OID_SUPPORTEDRATES, 0x17000010, - u8[IWMAX_BITRATES + 1], OID_TYPE_RAW), - OID_U32_C(DOT11_OID_FREQUENCY, 0x17000011), - [DOT11_OID_SUPPORTEDFREQUENCIES] = - {0x17000012, 0, sizeof (struct obj_frequencies) - + sizeof (u16) * IWMAX_FREQ, OID_TYPE_FREQUENCIES}, - - OID_U32(DOT11_OID_NOISEFLOOR, 0x17000013), - OID_STRUCT(DOT11_OID_FREQUENCYACTIVITY, 0x17000014, u8[IWMAX_FREQ + 1], - OID_TYPE_RAW), - OID_UNKNOWN(DOT11_OID_IQCALIBRATIONTABLE, 0x17000015), - OID_U32(DOT11_OID_NONERPPROTECTION, 0x17000016), - OID_U32(DOT11_OID_SLOTSETTINGS, 0x17000017), - OID_U32(DOT11_OID_NONERPTIMEOUT, 0x17000018), - OID_U32(DOT11_OID_PROFILES, 0x17000019), - OID_STRUCT(DOT11_OID_EXTENDEDRATES, 0x17000020, - u8[IWMAX_BITRATES + 1], OID_TYPE_RAW), - - OID_STRUCT_MLME(DOT11_OID_DEAUTHENTICATE, 0x18000000), - OID_STRUCT_MLME(DOT11_OID_AUTHENTICATE, 0x18000001), - OID_STRUCT_MLME(DOT11_OID_DISASSOCIATE, 0x18000002), - OID_STRUCT_MLME(DOT11_OID_ASSOCIATE, 0x18000003), - OID_UNKNOWN(DOT11_OID_SCAN, 0x18000004), - OID_STRUCT_MLMEEX(DOT11_OID_BEACON, 0x18000005), - OID_STRUCT_MLMEEX(DOT11_OID_PROBE, 0x18000006), - OID_STRUCT_MLMEEX(DOT11_OID_DEAUTHENTICATEEX, 0x18000007), - OID_STRUCT_MLMEEX(DOT11_OID_AUTHENTICATEEX, 0x18000008), - OID_STRUCT_MLMEEX(DOT11_OID_DISASSOCIATEEX, 0x18000009), - OID_STRUCT_MLMEEX(DOT11_OID_ASSOCIATEEX, 0x1800000A), - OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATE, 0x1800000B), - OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATEEX, 0x1800000C), - - OID_U32(DOT11_OID_NONERPSTATUS, 0x1E000000), - - OID_U32(DOT11_OID_STATIMEOUT, 0x19000000), - OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001), - OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002), - [DOT11_OID_ATTACHMENT] = {0x19000003, 0, - sizeof(struct obj_attachment), OID_TYPE_ATTACH}, - OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer, - OID_TYPE_BUFFER), - - OID_U32(DOT11_OID_BSSS, 0x1C000000), - [DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss), - OID_TYPE_BSS}, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ - OID_STRUCT(DOT11_OID_BSSFIND, 0x1C000042, struct obj_bss, OID_TYPE_BSS), - [DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct - obj_bsslist) + - sizeof (struct obj_bss[IWMAX_BSS]), - OID_TYPE_BSSLIST}, - - OID_UNKNOWN(OID_INL_TUNNEL, 0xFF020000), - OID_UNKNOWN(OID_INL_MEMADDR, 0xFF020001), - OID_UNKNOWN(OID_INL_MEMORY, 0xFF020002), - OID_U32_C(OID_INL_MODE, 0xFF020003), - OID_UNKNOWN(OID_INL_COMPONENT_NR, 0xFF020004), - OID_STRUCT(OID_INL_VERSION, 0xFF020005, u8[8], OID_TYPE_RAW), - OID_UNKNOWN(OID_INL_INTERFACE_ID, 0xFF020006), - OID_UNKNOWN(OID_INL_COMPONENT_ID, 0xFF020007), - OID_U32_C(OID_INL_CONFIG, 0xFF020008), - OID_U32_C(OID_INL_DOT11D_CONFORMANCE, 0xFF02000C), - OID_U32(OID_INL_PHYCAPABILITIES, 0xFF02000D), - OID_U32_C(OID_INL_OUTPUTPOWER, 0xFF02000F), - -}; - -int -mgt_init(islpci_private *priv) -{ - int i; - - priv->mib = kcalloc(OID_NUM_LAST, sizeof (void *), GFP_KERNEL); - if (!priv->mib) - return -ENOMEM; - - /* Alloc the cache */ - for (i = 0; i < OID_NUM_LAST; i++) { - if (isl_oid[i].flags & OID_FLAG_CACHED) { - priv->mib[i] = kcalloc(isl_oid[i].size, - (isl_oid[i].range + 1), - GFP_KERNEL); - if (!priv->mib[i]) - return -ENOMEM; - } else - priv->mib[i] = NULL; - } - - init_rwsem(&priv->mib_sem); - prism54_mib_init(priv); - - return 0; -} - -void -mgt_clean(islpci_private *priv) -{ - int i; - - if (!priv->mib) - return; - for (i = 0; i < OID_NUM_LAST; i++) { - kfree(priv->mib[i]); - priv->mib[i] = NULL; - } - kfree(priv->mib); - priv->mib = NULL; -} - -void -mgt_le_to_cpu(int type, void *data) -{ - switch (type) { - case OID_TYPE_U32: - *(u32 *) data = le32_to_cpu(*(u32 *) data); - break; - case OID_TYPE_BUFFER:{ - struct obj_buffer *buff = data; - buff->size = le32_to_cpu(buff->size); - buff->addr = le32_to_cpu(buff->addr); - break; - } - case OID_TYPE_BSS:{ - struct obj_bss *bss = data; - bss->age = le16_to_cpu(bss->age); - bss->channel = le16_to_cpu(bss->channel); - bss->capinfo = le16_to_cpu(bss->capinfo); - bss->rates = le16_to_cpu(bss->rates); - bss->basic_rates = le16_to_cpu(bss->basic_rates); - break; - } - case OID_TYPE_BSSLIST:{ - struct obj_bsslist *list = data; - int i; - list->nr = le32_to_cpu(list->nr); - for (i = 0; i < list->nr; i++) - mgt_le_to_cpu(OID_TYPE_BSS, &list->bsslist[i]); - break; - } - case OID_TYPE_FREQUENCIES:{ - struct obj_frequencies *freq = data; - int i; - freq->nr = le16_to_cpu(freq->nr); - for (i = 0; i < freq->nr; i++) - freq->mhz[i] = le16_to_cpu(freq->mhz[i]); - break; - } - case OID_TYPE_MLME:{ - struct obj_mlme *mlme = data; - mlme->id = le16_to_cpu(mlme->id); - mlme->state = le16_to_cpu(mlme->state); - mlme->code = le16_to_cpu(mlme->code); - break; - } - case OID_TYPE_MLMEEX:{ - struct obj_mlmeex *mlme = data; - mlme->id = le16_to_cpu(mlme->id); - mlme->state = le16_to_cpu(mlme->state); - mlme->code = le16_to_cpu(mlme->code); - mlme->size = le16_to_cpu(mlme->size); - break; - } - case OID_TYPE_ATTACH:{ - struct obj_attachment *attach = data; - attach->id = le16_to_cpu(attach->id); - attach->size = le16_to_cpu(attach->size); - break; - } - case OID_TYPE_SSID: - case OID_TYPE_KEY: - case OID_TYPE_ADDR: - case OID_TYPE_RAW: - break; - default: - BUG(); - } -} - -static void -mgt_cpu_to_le(int type, void *data) -{ - switch (type) { - case OID_TYPE_U32: - *(u32 *) data = cpu_to_le32(*(u32 *) data); - break; - case OID_TYPE_BUFFER:{ - struct obj_buffer *buff = data; - buff->size = cpu_to_le32(buff->size); - buff->addr = cpu_to_le32(buff->addr); - break; - } - case OID_TYPE_BSS:{ - struct obj_bss *bss = data; - bss->age = cpu_to_le16(bss->age); - bss->channel = cpu_to_le16(bss->channel); - bss->capinfo = cpu_to_le16(bss->capinfo); - bss->rates = cpu_to_le16(bss->rates); - bss->basic_rates = cpu_to_le16(bss->basic_rates); - break; - } - case OID_TYPE_BSSLIST:{ - struct obj_bsslist *list = data; - int i; - list->nr = cpu_to_le32(list->nr); - for (i = 0; i < list->nr; i++) - mgt_cpu_to_le(OID_TYPE_BSS, &list->bsslist[i]); - break; - } - case OID_TYPE_FREQUENCIES:{ - struct obj_frequencies *freq = data; - int i; - freq->nr = cpu_to_le16(freq->nr); - for (i = 0; i < freq->nr; i++) - freq->mhz[i] = cpu_to_le16(freq->mhz[i]); - break; - } - case OID_TYPE_MLME:{ - struct obj_mlme *mlme = data; - mlme->id = cpu_to_le16(mlme->id); - mlme->state = cpu_to_le16(mlme->state); - mlme->code = cpu_to_le16(mlme->code); - break; - } - case OID_TYPE_MLMEEX:{ - struct obj_mlmeex *mlme = data; - mlme->id = cpu_to_le16(mlme->id); - mlme->state = cpu_to_le16(mlme->state); - mlme->code = cpu_to_le16(mlme->code); - mlme->size = cpu_to_le16(mlme->size); - break; - } - case OID_TYPE_ATTACH:{ - struct obj_attachment *attach = data; - attach->id = cpu_to_le16(attach->id); - attach->size = cpu_to_le16(attach->size); - break; - } - case OID_TYPE_SSID: - case OID_TYPE_KEY: - case OID_TYPE_ADDR: - case OID_TYPE_RAW: - break; - default: - BUG(); - } -} - -/* Note : data is modified during this function */ - -int -mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data) -{ - int ret = 0; - struct islpci_mgmtframe *response = NULL; - int response_op = PIMFOR_OP_ERROR; - int dlen; - void *cache, *_data = data; - u32 oid; - - BUG_ON(n >= OID_NUM_LAST); - BUG_ON(extra > isl_oid[n].range); - - if (!priv->mib) - /* memory has been freed */ - return -1; - - dlen = isl_oid[n].size; - cache = priv->mib[n]; - cache += (cache ? extra * dlen : 0); - oid = isl_oid[n].oid + extra; - - if (_data == NULL) - /* we are requested to re-set a cached value */ - _data = cache; - else - mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, _data); - /* If we are going to write to the cache, we don't want anyone to read - * it -> acquire write lock. - * Else we could acquire a read lock to be sure we don't bother the - * commit process (which takes a write lock). But I'm not sure if it's - * needed. - */ - if (cache) - down_write(&priv->mib_sem); - - if (islpci_get_state(priv) >= PRV_STATE_READY) { - ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, - _data, dlen, &response); - if (!ret) { - response_op = response->header->operation; - islpci_mgt_release(response); - } - if (ret || response_op == PIMFOR_OP_ERROR) - ret = -EIO; - } else if (!cache) - ret = -EIO; - - if (cache) { - if (!ret && data) - memcpy(cache, _data, dlen); - up_write(&priv->mib_sem); - } - - /* re-set given data to what it was */ - if (data) - mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data); - - return ret; -} - -/* None of these are cached */ -int -mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len) -{ - int ret = 0; - struct islpci_mgmtframe *response; - int response_op = PIMFOR_OP_ERROR; - int dlen; - u32 oid; - - BUG_ON(n >= OID_NUM_LAST); - - dlen = isl_oid[n].size; - oid = isl_oid[n].oid; - - mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data); - - if (islpci_get_state(priv) >= PRV_STATE_READY) { - ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, - data, dlen + extra_len, &response); - if (!ret) { - response_op = response->header->operation; - islpci_mgt_release(response); - } - if (ret || response_op == PIMFOR_OP_ERROR) - ret = -EIO; - } else - ret = -EIO; - - /* re-set given data to what it was */ - if (data) - mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data); - - return ret; -} - -int -mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, - union oid_res_t *res) -{ - - int ret = -EIO; - int reslen = 0; - struct islpci_mgmtframe *response = NULL; - - int dlen; - void *cache, *_res = NULL; - u32 oid; - - BUG_ON(n >= OID_NUM_LAST); - BUG_ON(extra > isl_oid[n].range); - - res->ptr = NULL; - - if (!priv->mib) - /* memory has been freed */ - return -1; - - dlen = isl_oid[n].size; - cache = priv->mib[n]; - cache += cache ? extra * dlen : 0; - oid = isl_oid[n].oid + extra; - reslen = dlen; - - if (cache) - down_read(&priv->mib_sem); - - if (islpci_get_state(priv) >= PRV_STATE_READY) { - ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, - oid, data, dlen, &response); - if (ret || !response || - response->header->operation == PIMFOR_OP_ERROR) { - if (response) - islpci_mgt_release(response); - ret = -EIO; - } - if (!ret) { - _res = response->data; - reslen = response->header->length; - } - } else if (cache) { - _res = cache; - ret = 0; - } - if ((isl_oid[n].flags & OID_FLAG_TYPE) == OID_TYPE_U32) - res->u = ret ? 0 : le32_to_cpu(*(u32 *) _res); - else { - res->ptr = kmalloc(reslen, GFP_KERNEL); - BUG_ON(res->ptr == NULL); - if (ret) - memset(res->ptr, 0, reslen); - else { - memcpy(res->ptr, _res, reslen); - mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, - res->ptr); - } - } - if (cache) - up_read(&priv->mib_sem); - - if (response && !ret) - islpci_mgt_release(response); - - if (reslen > isl_oid[n].size) - printk(KERN_DEBUG - "mgt_get_request(0x%x): received data length was bigger " - "than expected (%d > %d). Memory is probably corrupted...", - oid, reslen, isl_oid[n].size); - - return ret; -} - -/* lock outside */ -int -mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n) -{ - int i, ret = 0; - struct islpci_mgmtframe *response; - - for (i = 0; i < n; i++) { - struct oid_t *t = &(isl_oid[l[i]]); - void *data = priv->mib[l[i]]; - int j = 0; - u32 oid = t->oid; - BUG_ON(data == NULL); - while (j <= t->range) { - int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, - oid, data, t->size, - &response); - if (response) { - r |= (response->header->operation == PIMFOR_OP_ERROR); - islpci_mgt_release(response); - } - if (r) - printk(KERN_ERR "%s: mgt_commit_list: failure. " - "oid=%08x err=%d\n", - priv->ndev->name, oid, r); - ret |= r; - j++; - oid++; - data += t->size; - } - } - return ret; -} - -/* Lock outside */ - -void -mgt_set(islpci_private *priv, enum oid_num_t n, void *data) -{ - BUG_ON(n >= OID_NUM_LAST); - BUG_ON(priv->mib[n] == NULL); - - memcpy(priv->mib[n], data, isl_oid[n].size); - mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, priv->mib[n]); -} - -void -mgt_get(islpci_private *priv, enum oid_num_t n, void *res) -{ - BUG_ON(n >= OID_NUM_LAST); - BUG_ON(priv->mib[n] == NULL); - BUG_ON(res == NULL); - - memcpy(res, priv->mib[n], isl_oid[n].size); - mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, res); -} - -/* Commits the cache. Lock outside. */ - -static enum oid_num_t commit_part1[] = { - OID_INL_CONFIG, - OID_INL_MODE, - DOT11_OID_BSSTYPE, - DOT11_OID_CHANNEL, - DOT11_OID_MLMEAUTOLEVEL -}; - -static enum oid_num_t commit_part2[] = { - DOT11_OID_SSID, - DOT11_OID_PSMBUFFER, - DOT11_OID_AUTHENABLE, - DOT11_OID_PRIVACYINVOKED, - DOT11_OID_EXUNENCRYPTED, - DOT11_OID_DEFKEYX, /* MULTIPLE */ - DOT11_OID_DEFKEYID, - DOT11_OID_DOT1XENABLE, - OID_INL_DOT11D_CONFORMANCE, - /* Do not initialize this - fw < 1.0.4.3 rejects it - OID_INL_OUTPUTPOWER, - */ -}; - -/* update the MAC addr. */ -static int -mgt_update_addr(islpci_private *priv) -{ - struct islpci_mgmtframe *res; - int ret; - - ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, - isl_oid[GEN_OID_MACADDRESS].oid, NULL, - isl_oid[GEN_OID_MACADDRESS].size, &res); - - if ((ret == 0) && res && (res->header->operation != PIMFOR_OP_ERROR)) - memcpy(priv->ndev->dev_addr, res->data, ETH_ALEN); - else - ret = -EIO; - if (res) - islpci_mgt_release(res); - - if (ret) - printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name); - return ret; -} - -int -mgt_commit(islpci_private *priv) -{ - int rvalue; - enum oid_num_t u; - - if (islpci_get_state(priv) < PRV_STATE_INIT) - return 0; - - rvalue = mgt_commit_list(priv, commit_part1, ARRAY_SIZE(commit_part1)); - - if (priv->iw_mode != IW_MODE_MONITOR) - rvalue |= mgt_commit_list(priv, commit_part2, ARRAY_SIZE(commit_part2)); - - u = OID_INL_MODE; - rvalue |= mgt_commit_list(priv, &u, 1); - rvalue |= mgt_update_addr(priv); - - if (rvalue) { - /* some request have failed. The device might be in an - incoherent state. We should reset it ! */ - printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name); - } - return rvalue; -} - -/* The following OIDs need to be "unlatched": - * - * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL - * FREQUENCY,EXTENDEDRATES. - * - * The way to do this is to set ESSID. Note though that they may get - * unlatch before though by setting another OID. */ -#if 0 -void -mgt_unlatch_all(islpci_private *priv) -{ - u32 u; - int rvalue = 0; - - if (islpci_get_state(priv) < PRV_STATE_INIT) - return; - - u = DOT11_OID_SSID; - rvalue = mgt_commit_list(priv, &u, 1); - /* Necessary if in MANUAL RUN mode? */ -#if 0 - u = OID_INL_MODE; - rvalue |= mgt_commit_list(priv, &u, 1); - - u = DOT11_OID_MLMEAUTOLEVEL; - rvalue |= mgt_commit_list(priv, &u, 1); - - u = OID_INL_MODE; - rvalue |= mgt_commit_list(priv, &u, 1); -#endif - - if (rvalue) - printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name); -} -#endif - -/* This will tell you if you are allowed to answer a mlme(ex) request .*/ - -int -mgt_mlme_answer(islpci_private *priv) -{ - u32 mlmeautolevel; - /* Acquire a read lock because if we are in a mode change, it's - * possible to answer true, while the card is leaving master to managed - * mode. Answering to a mlme in this situation could hang the card. - */ - down_read(&priv->mib_sem); - mlmeautolevel = - le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]); - up_read(&priv->mib_sem); - - return ((priv->iw_mode == IW_MODE_MASTER) && - (mlmeautolevel >= DOT11_MLME_INTERMEDIATE)); -} - -enum oid_num_t -mgt_oidtonum(u32 oid) -{ - int i; - - for (i = 0; i < OID_NUM_LAST; i++) - if (isl_oid[i].oid == oid) - return i; - - printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid); - - return OID_NUM_LAST; -} - -int -mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str) -{ - switch (isl_oid[n].flags & OID_FLAG_TYPE) { - case OID_TYPE_U32: - return scnprintf(str, PRIV_STR_SIZE, "%u\n", r->u); - case OID_TYPE_BUFFER:{ - struct obj_buffer *buff = r->ptr; - return scnprintf(str, PRIV_STR_SIZE, - "size=%u\naddr=0x%X\n", buff->size, - buff->addr); - } - break; - case OID_TYPE_BSS:{ - struct obj_bss *bss = r->ptr; - return scnprintf(str, PRIV_STR_SIZE, - "age=%u\nchannel=%u\n" - "capinfo=0x%X\nrates=0x%X\n" - "basic_rates=0x%X\n", bss->age, - bss->channel, bss->capinfo, - bss->rates, bss->basic_rates); - } - break; - case OID_TYPE_BSSLIST:{ - struct obj_bsslist *list = r->ptr; - int i, k; - k = scnprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr); - for (i = 0; i < list->nr; i++) - k += scnprintf(str + k, PRIV_STR_SIZE - k, - "bss[%u] :\nage=%u\nchannel=%u\n" - "capinfo=0x%X\nrates=0x%X\n" - "basic_rates=0x%X\n", - i, list->bsslist[i].age, - list->bsslist[i].channel, - list->bsslist[i].capinfo, - list->bsslist[i].rates, - list->bsslist[i].basic_rates); - return k; - } - break; - case OID_TYPE_FREQUENCIES:{ - struct obj_frequencies *freq = r->ptr; - int i, t; - printk("nr : %u\n", freq->nr); - t = scnprintf(str, PRIV_STR_SIZE, "nr=%u\n", freq->nr); - for (i = 0; i < freq->nr; i++) - t += scnprintf(str + t, PRIV_STR_SIZE - t, - "mhz[%u]=%u\n", i, freq->mhz[i]); - return t; - } - break; - case OID_TYPE_MLME:{ - struct obj_mlme *mlme = r->ptr; - return scnprintf(str, PRIV_STR_SIZE, - "id=0x%X\nstate=0x%X\ncode=0x%X\n", - mlme->id, mlme->state, mlme->code); - } - break; - case OID_TYPE_MLMEEX:{ - struct obj_mlmeex *mlme = r->ptr; - return scnprintf(str, PRIV_STR_SIZE, - "id=0x%X\nstate=0x%X\n" - "code=0x%X\nsize=0x%X\n", mlme->id, - mlme->state, mlme->code, mlme->size); - } - break; - case OID_TYPE_ATTACH:{ - struct obj_attachment *attach = r->ptr; - return scnprintf(str, PRIV_STR_SIZE, - "id=%d\nsize=%d\n", - attach->id, - attach->size); - } - break; - case OID_TYPE_SSID:{ - struct obj_ssid *ssid = r->ptr; - return scnprintf(str, PRIV_STR_SIZE, - "length=%u\noctets=%.*s\n", - ssid->length, ssid->length, - ssid->octets); - } - break; - case OID_TYPE_KEY:{ - struct obj_key *key = r->ptr; - int t, i; - t = scnprintf(str, PRIV_STR_SIZE, - "type=0x%X\nlength=0x%X\nkey=0x", - key->type, key->length); - for (i = 0; i < key->length; i++) - t += scnprintf(str + t, PRIV_STR_SIZE - t, - "%02X:", key->key[i]); - t += scnprintf(str + t, PRIV_STR_SIZE - t, "\n"); - return t; - } - break; - case OID_TYPE_RAW: - case OID_TYPE_ADDR:{ - unsigned char *buff = r->ptr; - int t, i; - t = scnprintf(str, PRIV_STR_SIZE, "hex data="); - for (i = 0; i < isl_oid[n].size; i++) - t += scnprintf(str + t, PRIV_STR_SIZE - t, - "%02X:", buff[i]); - t += scnprintf(str + t, PRIV_STR_SIZE - t, "\n"); - return t; - } - break; - default: - BUG(); - } - return 0; -} diff --git a/drivers/net/wireless/intersil/prism54/oid_mgt.h b/drivers/net/wireless/intersil/prism54/oid_mgt.h deleted file mode 100644 index a7dc9e24c0bf..000000000000 --- a/drivers/net/wireless/intersil/prism54/oid_mgt.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2003 Aurelien Alleaume <slts@free.fr> - */ - -#if !defined(_OID_MGT_H) -#define _OID_MGT_H - -#include "isl_oid.h" -#include "islpci_dev.h" - -extern struct oid_t isl_oid[]; - -int mgt_init(islpci_private *); - -void mgt_clean(islpci_private *); - -/* I don't know where to put these 2 */ -extern const int frequency_list_a[]; -int channel_of_freq(int); - -void mgt_le_to_cpu(int, void *); - -int mgt_set_request(islpci_private *, enum oid_num_t, int, void *); -int mgt_set_varlen(islpci_private *, enum oid_num_t, void *, int); - - -int mgt_get_request(islpci_private *, enum oid_num_t, int, void *, - union oid_res_t *); - -int mgt_commit_list(islpci_private *, enum oid_num_t *, int); - -void mgt_set(islpci_private *, enum oid_num_t, void *); - -void mgt_get(islpci_private *, enum oid_num_t, void *); - -int mgt_commit(islpci_private *); - -int mgt_mlme_answer(islpci_private *); - -enum oid_num_t mgt_oidtonum(u32 oid); - -int mgt_response_to_str(enum oid_num_t, union oid_res_t *, char *); - -#endif /* !defined(_OID_MGT_H) */ -/* EOF */ diff --git a/drivers/net/wireless/intersil/prism54/prismcompat.h b/drivers/net/wireless/intersil/prism54/prismcompat.h deleted file mode 100644 index c4489b66d07e..000000000000 --- a/drivers/net/wireless/intersil/prism54/prismcompat.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * (C) 2004 Margit Schubert-While <margitsw@t-online.de> - */ - -/* - * Compatibility header file to aid support of different kernel versions - */ - -#ifdef PRISM54_COMPAT24 -#include "prismcompat24.h" -#else /* PRISM54_COMPAT24 */ - -#ifndef _PRISM_COMPAT_H -#define _PRISM_COMPAT_H - -#include <linux/device.h> -#include <linux/firmware.h> -#include <linux/moduleparam.h> -#include <linux/workqueue.h> -#include <linux/compiler.h> - -#ifndef __iomem -#define __iomem -#endif - -#define PRISM_FW_PDEV &priv->pdev->dev - -#endif /* _PRISM_COMPAT_H */ -#endif /* PRISM54_COMPAT24 */ diff --git a/drivers/net/wireless/marvell/libertas/ethtool.c b/drivers/net/wireless/marvell/libertas/ethtool.c index 1bb8746a0b23..d8e4f29b690d 100644 --- a/drivers/net/wireless/marvell/libertas/ethtool.c +++ b/drivers/net/wireless/marvell/libertas/ethtool.c @@ -43,10 +43,8 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev, int ret; if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN || - eeprom->len > LBS_EEPROM_READ_LEN) { - ret = -EINVAL; - goto out; - } + eeprom->len > LBS_EEPROM_READ_LEN) + return -EINVAL; cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) - LBS_EEPROM_READ_LEN + eeprom->len); @@ -57,8 +55,7 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev, if (!ret) memcpy(bytes, cmd.value, eeprom->len); -out: - return ret; + return ret; } static void lbs_ethtool_get_wol(struct net_device *dev, diff --git a/drivers/net/wireless/marvell/mwifiex/Makefile b/drivers/net/wireless/marvell/mwifiex/Makefile index 162d557b78af..2bd00f40958e 100644 --- a/drivers/net/wireless/marvell/mwifiex/Makefile +++ b/drivers/net/wireless/marvell/mwifiex/Makefile @@ -49,6 +49,7 @@ mwifiex_sdio-y += sdio.o obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o mwifiex_pcie-y += pcie.o +mwifiex_pcie-y += pcie_quirks.o obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o mwifiex_usb-y += usb.o diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 3a11342a6bde..171a25742600 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -187,7 +187,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); /* Sanity test */ - if (host_cmd == NULL || host_cmd->size == 0) { + if (host_cmd->size == 0) { mwifiex_dbg(adapter, ERROR, "DNLD_CMD: host_cmd is null\t" "or cmd size is 0, not sending\n"); diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 46517515ba72..c6ccce426b49 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -27,6 +27,7 @@ #include "wmm.h" #include "11n.h" #include "pcie.h" +#include "pcie_quirks.h" #define PCIE_VERSION "1.0" #define DRV_NAME "Marvell mwifiex PCIe" @@ -410,6 +411,9 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, return ret; } + /* check quirks */ + mwifiex_initialize_quirks(card); + if (mwifiex_add_card(card, &card->fw_done, &pcie_ops, MWIFIEX_PCIE, &pdev->dev)) { pr_err("%s failed\n", __func__); @@ -524,6 +528,13 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev) mwifiex_shutdown_sw(adapter); clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); + + /* On MS Surface gen4+ devices FLR isn't effective to recover from + * hangups, so we power-cycle the card instead. + */ + if (card->quirks & QUIRK_FW_RST_D3COLD) + mwifiex_pcie_reset_d3cold_quirk(pdev); + mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); card->pci_reset_ongoing = true; diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 5ed613d65709..981e330c77d7 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -244,6 +244,7 @@ struct pcie_service_card { unsigned long work_flags; bool pci_reset_ongoing; + unsigned long quirks; }; static inline int diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c new file mode 100644 index 000000000000..0234cf3c2974 --- /dev/null +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -0,0 +1,161 @@ +/* + * NXP Wireless LAN device driver: PCIE and platform specific quirks + * + * This software file (the "File") is distributed by NXP + * under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include <linux/dmi.h> + +#include "pcie_quirks.h" + +/* quirk table based on DMI matching */ +static const struct dmi_system_id mwifiex_quirk_table[] = { + { + .ident = "Surface Pro 4", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 5", + .matches = { + /* match for SKU here due to generic product name "Surface Pro" */ + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 5 (LTE)", + .matches = { + /* match for SKU here due to generic product name "Surface Pro" */ + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 6", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Book 1", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Book 2", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Laptop 1", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Laptop 2", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + {} +}; + +void mwifiex_initialize_quirks(struct pcie_service_card *card) +{ + struct pci_dev *pdev = card->dev; + const struct dmi_system_id *dmi_id; + + dmi_id = dmi_first_match(mwifiex_quirk_table); + if (dmi_id) + card->quirks = (uintptr_t)dmi_id->driver_data; + + if (!card->quirks) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); +} + +static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +{ + dev_info(&pdev->dev, "putting into D3cold...\n"); + + pci_save_state(pdev); + if (pci_is_enabled(pdev)) + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3cold); +} + +static int mwifiex_pcie_set_power_d0(struct pci_dev *pdev) +{ + int ret; + + dev_info(&pdev->dev, "putting into D0...\n"); + + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_enable_device failed\n"); + return ret; + } + pci_restore_state(pdev); + + return 0; +} + +int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev) +{ + struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + /* Power-cycle (put into D3cold then D0) */ + dev_info(&pdev->dev, "Using reset_d3cold quirk to perform FW reset\n"); + + /* We need to perform power-cycle also for bridge of wifi because + * on some devices (e.g. Surface Book 1), the OS for some reasons + * can't know the real power state of the bridge. + * When tried to power-cycle only wifi, the reset failed with the + * following dmesg log: + * "Cannot transition to power state D0 for parent in D3hot". + */ + mwifiex_pcie_set_power_d3cold(pdev); + mwifiex_pcie_set_power_d3cold(parent_pdev); + + ret = mwifiex_pcie_set_power_d0(parent_pdev); + if (ret) + return ret; + ret = mwifiex_pcie_set_power_d0(pdev); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h new file mode 100644 index 000000000000..8ec4176d698f --- /dev/null +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -0,0 +1,23 @@ +/* + * NXP Wireless LAN device driver: PCIE and platform specific quirks + * + * This software file (the "File") is distributed by NXP + * under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "pcie.h" + +#define QUIRK_FW_RST_D3COLD BIT(0) + +void mwifiex_initialize_quirks(struct pcie_service_card *card); +int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 653f9e094256..4062e515697a 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -1325,8 +1325,8 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, u16 ie_len) { struct ieee_types_vendor_header *pvendor_ie; - const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; - const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; + static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; + static const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; u16 unparsed_len = ie_len, cur_ie_len; /* If the passed length is zero, reset the buffer */ diff --git a/drivers/net/wireless/marvell/mwifiex/usb.h b/drivers/net/wireless/marvell/mwifiex/usb.h index d822ec15b7e6..61a96b7fbf21 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.h +++ b/drivers/net/wireless/marvell/mwifiex/usb.h @@ -134,7 +134,7 @@ struct fw_sync_header { struct fw_data { struct fw_header fw_hdr; __le32 seq_num; - u8 data[1]; + u8 data[]; } __packed; #endif /*_MWIFIEX_USB_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 863aa18b3024..43960770a9af 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -111,7 +111,7 @@ mt7915_mcu_get_cipher(int cipher) case WLAN_CIPHER_SUITE_SMS4: return MCU_CIPHER_WAPI; default: - return MT_CIPHER_NONE; + return MCU_CIPHER_NONE; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index edd3ba3a0c2d..e68a562cc5b4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -1073,7 +1073,8 @@ enum { }; enum mcu_cipher_type { - MCU_CIPHER_WEP40 = 1, + MCU_CIPHER_NONE = 0, + MCU_CIPHER_WEP40, MCU_CIPHER_WEP104, MCU_CIPHER_WEP128, MCU_CIPHER_TKIP, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index cd690c64f65b..9fbaacc67cfa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -111,7 +111,7 @@ mt7921_mcu_get_cipher(int cipher) case WLAN_CIPHER_SUITE_SMS4: return MCU_CIPHER_WAPI; default: - return MT_CIPHER_NONE; + return MCU_CIPHER_NONE; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index d76cf8f8dfdf..de3c091f6736 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -199,7 +199,8 @@ struct sta_rec_sec { } __packed; enum mcu_cipher_type { - MCU_CIPHER_WEP40 = 1, + MCU_CIPHER_NONE = 0, + MCU_CIPHER_WEP40, MCU_CIPHER_WEP104, MCU_CIPHER_WEP128, MCU_CIPHER_TKIP, diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index e14b9fc2c67a..42e03a701ae1 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -129,10 +129,8 @@ static int wilc_sdio_probe(struct sdio_func *func, ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO, &wilc_hif_sdio); - if (ret) { - kfree(sdio_priv); - return ret; - } + if (ret) + goto free; if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) { struct device_node *np = func->card->dev.of_node; @@ -148,24 +146,29 @@ static int wilc_sdio_probe(struct sdio_func *func, wilc->bus_data = sdio_priv; wilc->dev = &func->dev; - wilc->rtc_clk = devm_clk_get(&func->card->dev, "rtc"); - if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) { - kfree(sdio_priv); - return -EPROBE_DEFER; - } else if (!IS_ERR(wilc->rtc_clk)) - clk_prepare_enable(wilc->rtc_clk); + wilc->rtc_clk = devm_clk_get_optional(&func->card->dev, "rtc"); + if (IS_ERR(wilc->rtc_clk)) { + ret = PTR_ERR(wilc->rtc_clk); + goto dispose_irq; + } + clk_prepare_enable(wilc->rtc_clk); dev_info(&func->dev, "Driver Initializing success\n"); return 0; + +dispose_irq: + irq_dispose_mapping(wilc->dev_irq_num); + wilc_netdev_cleanup(wilc); +free: + kfree(sdio_priv); + return ret; } static void wilc_sdio_remove(struct sdio_func *func) { struct wilc *wilc = sdio_get_drvdata(func); - if (!IS_ERR(wilc->rtc_clk)) - clk_disable_unprepare(wilc->rtc_clk); - + clk_disable_unprepare(wilc->rtc_clk); wilc_netdev_cleanup(wilc); } diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 8e9aaf03a6fa..dd481dc0b5ce 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -39,6 +39,7 @@ MODULE_PARM_DESC(enable_crc16, #define WILC_SPI_RSP_HDR_EXTRA_DATA 8 struct wilc_spi { + bool isinit; /* true if SPI protocol has been configured */ bool probing_crc; /* true if we're probing chip's CRC config */ bool crc7_enabled; /* true if crc7 is currently enabled */ bool crc16_enabled; /* true if crc16 is currently enabled */ @@ -154,34 +155,37 @@ static int wilc_bus_probe(struct spi_device *spi) return -ENOMEM; ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi); - if (ret) { - kfree(spi_priv); - return ret; - } + if (ret) + goto free; spi_set_drvdata(spi, wilc); wilc->dev = &spi->dev; wilc->bus_data = spi_priv; wilc->dev_irq_num = spi->irq; - wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc"); - if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) { - kfree(spi_priv); - return -EPROBE_DEFER; - } else if (!IS_ERR(wilc->rtc_clk)) - clk_prepare_enable(wilc->rtc_clk); + wilc->rtc_clk = devm_clk_get_optional(&spi->dev, "rtc"); + if (IS_ERR(wilc->rtc_clk)) { + ret = PTR_ERR(wilc->rtc_clk); + goto netdev_cleanup; + } + clk_prepare_enable(wilc->rtc_clk); return 0; + +netdev_cleanup: + wilc_netdev_cleanup(wilc); +free: + kfree(spi_priv); + return ret; } static int wilc_bus_remove(struct spi_device *spi) { struct wilc *wilc = spi_get_drvdata(spi); - if (!IS_ERR(wilc->rtc_clk)) - clk_disable_unprepare(wilc->rtc_clk); - + clk_disable_unprepare(wilc->rtc_clk); wilc_netdev_cleanup(wilc); + return 0; } @@ -905,15 +909,15 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) struct wilc_spi *spi_priv = wilc->bus_data; u32 reg; u32 chipid; - static int isinit; int ret, i; - if (isinit) { + if (spi_priv->isinit) { + /* Confirm we can read chipid register without error: */ ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); - if (ret) - dev_err(&spi->dev, "Fail cmd read chip id...\n"); + if (ret == 0) + return 0; - return ret; + dev_err(&spi->dev, "Fail cmd read chip id...\n"); } /* @@ -971,7 +975,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) spi_priv->probing_crc = false; /* - * make sure can read back chip id correctly + * make sure can read chip id without protocol error */ ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); if (ret) { @@ -979,7 +983,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) return ret; } - isinit = 1; + spi_priv->isinit = true; return 0; } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 2030fc7f53ca..200a103a0a85 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -1127,27 +1127,22 @@ int wilc_wlan_start(struct wilc *wilc) } acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg); - if (ret) { - release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; - } + if (ret) + goto release; + reg = 0; if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num) reg |= WILC_HAVE_SDIO_IRQ_GPIO; ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg); - if (ret) { - release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; - } + if (ret) + goto release; wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT); ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); - if (ret) { - release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; - } + if (ret) + goto release; wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); if ((reg & BIT(10)) == BIT(10)) { @@ -1159,8 +1154,9 @@ int wilc_wlan_start(struct wilc *wilc) reg |= BIT(10); ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); +release: + release_bus(wilc, WILC_BUS_RELEASE_ONLY); return ret; } @@ -1174,36 +1170,34 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); if (ret) { netdev_err(vif->ndev, "Error while reading reg\n"); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); - return ret; + goto release; } ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, (reg | WILC_ABORT_REQ_BIT)); if (ret) { netdev_err(vif->ndev, "Error while writing reg\n"); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); - return ret; + goto release; } ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®); if (ret) { netdev_err(vif->ndev, "Error while reading reg\n"); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); - return ret; + goto release; } reg = BIT(0); ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg); if (ret) { netdev_err(vif->ndev, "Error while writing reg\n"); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); - return ret; + goto release; } + ret = 0; +release: release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); - return 0; + return ret; } void wilc_wlan_cleanup(struct net_device *dev) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 0003df577cb3..840728ed57b2 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -295,9 +295,9 @@ static int pearl_skb2rbd_attach(struct qtnf_pcie_pearl_state *ps, u16 index) priv->rx_skb[index] = skb; rxbd = &ps->rx_bd_vbase[index]; - paddr = pci_map_single(priv->pdev, skb->data, - SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pdev, paddr)) { + paddr = dma_map_single(&priv->pdev->dev, skb->data, SKB_BUF_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, paddr)) { pr_err("skb DMA mapping error: %pad\n", &paddr); return -ENOMEM; } @@ -357,8 +357,8 @@ static void qtnf_pearl_free_xfer_buffers(struct qtnf_pcie_pearl_state *ps) skb = priv->rx_skb[i]; paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), le32_to_cpu(rxbd->addr)); - pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, - PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, paddr, + SKB_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); priv->rx_skb[i] = NULL; } @@ -371,8 +371,8 @@ static void qtnf_pearl_free_xfer_buffers(struct qtnf_pcie_pearl_state *ps) skb = priv->tx_skb[i]; paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), le32_to_cpu(txbd->addr)); - pci_unmap_single(priv->pdev, paddr, skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pdev->dev, paddr, skb->len, + DMA_TO_DEVICE); dev_kfree_skb_any(skb); priv->tx_skb[i] = NULL; } @@ -485,8 +485,8 @@ static void qtnf_pearl_data_tx_reclaim(struct qtnf_pcie_pearl_state *ps) txbd = &ps->tx_bd_vbase[i]; paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), le32_to_cpu(txbd->addr)); - pci_unmap_single(priv->pdev, paddr, skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pdev->dev, paddr, skb->len, + DMA_TO_DEVICE); if (skb->dev) { dev_sw_netstats_tx_add(skb->dev, 1, skb->len); @@ -559,9 +559,9 @@ static int qtnf_pcie_skb_send(struct qtnf_bus *bus, struct sk_buff *skb) priv->tx_skb[i] = skb; len = skb->len; - skb_paddr = pci_map_single(priv->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, skb_paddr)) { + skb_paddr = dma_map_single(&priv->pdev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, skb_paddr)) { pr_err("skb DMA mapping error: %pad\n", &skb_paddr); ret = -ENOMEM; goto tx_done; @@ -748,8 +748,8 @@ static int qtnf_pcie_pearl_rx_poll(struct napi_struct *napi, int budget) if (skb) { skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), le32_to_cpu(rxbd->addr)); - pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE, - PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, skb_paddr, + SKB_BUF_SIZE, DMA_FROM_DEVICE); } if (consume) { diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c index 24f1be8ddcef..9534e1b33780 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c @@ -255,9 +255,9 @@ topaz_skb2rbd_attach(struct qtnf_pcie_topaz_state *ts, u16 index, u32 wrap) ts->base.rx_skb[index] = skb; - paddr = pci_map_single(ts->base.pdev, skb->data, - SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(ts->base.pdev, paddr)) { + paddr = dma_map_single(&ts->base.pdev->dev, skb->data, SKB_BUF_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(&ts->base.pdev->dev, paddr)) { pr_err("skb mapping error: %pad\n", &paddr); return -ENOMEM; } @@ -306,8 +306,8 @@ static void qtnf_topaz_free_xfer_buffers(struct qtnf_pcie_topaz_state *ts) rxbd = &ts->rx_bd_vbase[i]; skb = priv->rx_skb[i]; paddr = QTN_HOST_ADDR(0x0, le32_to_cpu(rxbd->addr)); - pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, - PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, paddr, + SKB_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); priv->rx_skb[i] = NULL; rxbd->addr = 0; @@ -321,8 +321,8 @@ static void qtnf_topaz_free_xfer_buffers(struct qtnf_pcie_topaz_state *ts) txbd = &ts->tx_bd_vbase[i]; skb = priv->tx_skb[i]; paddr = QTN_HOST_ADDR(0x0, le32_to_cpu(txbd->addr)); - pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, - PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pdev->dev, paddr, + SKB_BUF_SIZE, DMA_TO_DEVICE); dev_kfree_skb_any(skb); priv->tx_skb[i] = NULL; txbd->addr = 0; @@ -414,8 +414,8 @@ static void qtnf_topaz_data_tx_reclaim(struct qtnf_pcie_topaz_state *ts) if (likely(skb)) { txbd = &ts->tx_bd_vbase[i]; paddr = QTN_HOST_ADDR(0x0, le32_to_cpu(txbd->addr)); - pci_unmap_single(priv->pdev, paddr, skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pdev->dev, paddr, skb->len, + DMA_TO_DEVICE); if (skb->dev) { dev_sw_netstats_tx_add(skb->dev, 1, skb->len); @@ -522,9 +522,9 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb, priv->tx_skb[i] = skb; len = skb->len; - skb_paddr = pci_map_single(priv->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, skb_paddr)) { + skb_paddr = dma_map_single(&priv->pdev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, skb_paddr)) { ret = -ENOMEM; goto tx_done; } @@ -653,8 +653,8 @@ static int qtnf_topaz_rx_poll(struct napi_struct *napi, int budget) if (skb) { skb_paddr = QTN_HOST_ADDR(0x0, le32_to_cpu(rxbd->addr)); - pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE, - PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, skb_paddr, + SKB_BUF_SIZE, DMA_FROM_DEVICE); } if (consume) { diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 590bd974d94f..0f5009c47cd0 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -982,7 +982,9 @@ AP to AP 1 1 dest AP src AP dest source if (local->net_type == ADHOC) { writeb(0, &ptx->mac.frame_ctl_2); memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, - 2 * ADDRLEN); + ADDRLEN); + memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, + ADDRLEN); memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); } else { /* infrastructure */ @@ -2424,9 +2426,7 @@ static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); /* if we are trying to get authenticated */ if (local->sparm.b4.a_network_type == ADHOC) { - pr_debug("ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", - msg->var[0], msg->var[1], msg->var[2], msg->var[3], - msg->var[4], msg->var[5]); + pr_debug("ray_cs rx_auth var= %6ph\n", msg->var); if (msg->var[2] == 1) { pr_debug("ray_cs Sending authentication response.\n"); if (!build_auth_frame diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 01735776345a..7ddce3c3f0c4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1378,6 +1378,8 @@ struct rtl8xxxu_priv { u8 no_pape:1; u8 int_buf[USB_INTR_CONTENT_LENGTH]; u8 rssi_level; + DECLARE_BITMAP(tx_aggr_started, IEEE80211_NUM_TIDS); + DECLARE_BITMAP(tid_tx_operational, IEEE80211_NUM_TIDS); /* * Only one virtual interface permitted because only STA mode * is supported and no iface_combinations are provided. diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index ac1061caacd6..774341b0005a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -1670,7 +1670,7 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) priv->rf_paths = 2; priv->rx_paths = 2; priv->tx_paths = 2; - priv->usb_interrupts = 1; + priv->usb_interrupts = 0; priv->rtl_chip = RTL8192C; } priv->has_wifi = 1; @@ -1680,7 +1680,7 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) priv->rx_paths = 1; priv->tx_paths = 1; priv->rtl_chip = RTL8188C; - priv->usb_interrupts = 1; + priv->usb_interrupts = 0; priv->has_wifi = 1; } @@ -4805,6 +4805,8 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; + u8 *qc = ieee80211_get_qos_ctl(hdr); + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u32 rate; u16 rate_flags = tx_info->control.rates[0].flags; u16 seq_number; @@ -4828,7 +4830,7 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC32_SEQ_SHIFT); - if (ampdu_enable) + if (ampdu_enable && test_bit(tid, priv->tid_tx_operational)) tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_ENABLE); else tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_BREAK); @@ -4876,6 +4878,8 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; struct rtl8xxxu_txdesc40 *tx_desc40; + u8 *qc = ieee80211_get_qos_ctl(hdr); + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u32 rate; u16 rate_flags = tx_info->control.rates[0].flags; u16 seq_number; @@ -4902,7 +4906,7 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, tx_desc40->txdw9 = cpu_to_le32((u32)seq_number << TXDESC40_SEQ_SHIFT); - if (ampdu_enable) + if (ampdu_enable && test_bit(tid, priv->tid_tx_operational)) tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_ENABLE); else tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_BREAK); @@ -5015,12 +5019,19 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, if (ieee80211_is_data_qos(hdr->frame_control) && sta) { if (sta->ht_cap.ht_supported) { u32 ampdu, val32; + u8 *qc = ieee80211_get_qos_ctl(hdr); + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; ampdu = (u32)sta->ht_cap.ampdu_density; val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT; tx_desc->txdw2 |= cpu_to_le32(val32); ampdu_enable = true; + + if (!test_bit(tid, priv->tx_aggr_started) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) + if (!ieee80211_start_tx_ba_session(sta, tid, 0)) + set_bit(tid, priv->tx_aggr_started); } } @@ -6096,6 +6107,7 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct device *dev = &priv->udev->dev; u8 ampdu_factor, ampdu_density; struct ieee80211_sta *sta = params->sta; + u16 tid = params->tid; enum ieee80211_ampdu_mlme_action action = params->action; switch (action) { @@ -6108,17 +6120,20 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, dev_dbg(dev, "Changed HT: ampdu_factor %02x, ampdu_density %02x\n", ampdu_factor, ampdu_density); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; + case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: - dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__); - rtl8xxxu_set_ampdu_factor(priv, 0); - rtl8xxxu_set_ampdu_min_space(priv, 0); - break; case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: - dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n", - __func__); + dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP\n", __func__); rtl8xxxu_set_ampdu_factor(priv, 0); rtl8xxxu_set_ampdu_min_space(priv, 0); + clear_bit(tid, priv->tx_aggr_started); + clear_bit(tid, priv->tid_tx_operational); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_OPERATIONAL\n", __func__); + set_bit(tid, priv->tid_tx_operational); break; case IEEE80211_AMPDU_RX_START: dev_dbg(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c index 76dd881ef9bb..9b83c710c9b8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c @@ -160,6 +160,15 @@ static u32 targetchnl_2g[TARGET_CHNL_NUM_2G] = { 25711, 25658, 25606, 25554, 25502, 25451, 25328 }; +static const u8 channel_all[59] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, + 114, 116, 118, 120, 122, 124, 126, 128, 130, + 132, 134, 136, 138, 140, 149, 151, 153, 155, + 157, 159, 161, 163, 165 +}; + static u32 _rtl92d_phy_calculate_bit_shift(u32 bitmask) { u32 i = ffs(bitmask); @@ -681,7 +690,7 @@ static bool _rtl92d_phy_bb_config(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - bool rtstatus = true; + bool rtstatus; rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "==>\n"); rtstatus = _rtl92d_phy_config_bb_with_headerfile(hw, @@ -1354,15 +1363,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) u8 rtl92d_get_rightchnlplace_for_iqk(u8 chnl) { - u8 channel_all[59] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, - 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, - 114, 116, 118, 120, 122, 124, 126, 128, 130, - 132, 134, 136, 138, 140, 149, 151, 153, 155, - 157, 159, 161, 163, 165 - }; - u8 place = chnl; + u8 place; if (chnl > 14) { for (place = 14; place < sizeof(channel_all); place++) { @@ -3220,37 +3221,28 @@ void rtl92d_phy_config_macphymode_info(struct ieee80211_hw *hw) u8 rtl92d_get_chnlgroup_fromarray(u8 chnl) { u8 group; - u8 channel_info[59] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, - 58, 60, 62, 64, 100, 102, 104, 106, 108, - 110, 112, 114, 116, 118, 120, 122, 124, - 126, 128, 130, 132, 134, 136, 138, 140, - 149, 151, 153, 155, 157, 159, 161, 163, - 165 - }; - if (channel_info[chnl] <= 3) + if (channel_all[chnl] <= 3) group = 0; - else if (channel_info[chnl] <= 9) + else if (channel_all[chnl] <= 9) group = 1; - else if (channel_info[chnl] <= 14) + else if (channel_all[chnl] <= 14) group = 2; - else if (channel_info[chnl] <= 44) + else if (channel_all[chnl] <= 44) group = 3; - else if (channel_info[chnl] <= 54) + else if (channel_all[chnl] <= 54) group = 4; - else if (channel_info[chnl] <= 64) + else if (channel_all[chnl] <= 64) group = 5; - else if (channel_info[chnl] <= 112) + else if (channel_all[chnl] <= 112) group = 6; - else if (channel_info[chnl] <= 126) + else if (channel_all[chnl] <= 126) group = 7; - else if (channel_info[chnl] <= 140) + else if (channel_all[chnl] <= 140) group = 8; - else if (channel_info[chnl] <= 153) + else if (channel_all[chnl] <= 153) group = 9; - else if (channel_info[chnl] <= 159) + else if (channel_all[chnl] <= 159) group = 10; else group = 11; diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index c0e4b111c8b4..73d6807a8cdf 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -15,9 +15,9 @@ rtw88_core-y += main.o \ ps.o \ sec.o \ bf.o \ - wow.o \ regd.o +rtw88_core-$(CONFIG_PM) += wow.o obj-$(CONFIG_RTW88_8822B) += rtw88_8822b.o rtw88_8822b-objs := rtw8822b.o rtw8822b_table.o diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 3bfa5ecc0053..e6399519584b 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -819,7 +819,7 @@ static u16 rtw_get_rsvd_page_probe_req_size(struct rtw_dev *rtwdev, continue; if ((!ssid && !rsvd_pkt->ssid) || rtw_ssid_equal(rsvd_pkt->ssid, ssid)) - size = rsvd_pkt->skb->len; + size = rsvd_pkt->probe_req_size; } return size; @@ -1047,6 +1047,8 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, ssid->ssid_len, 0); else skb_new = ieee80211_probereq_get(hw, vif->addr, NULL, 0, 0); + if (skb_new) + rsvd_pkt->probe_req_size = (u16)skb_new->len; break; case RSVD_NLO_INFO: skb_new = rtw_nlo_info_get(hw); @@ -1643,6 +1645,7 @@ int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size, static void __rtw_fw_update_pkt(struct rtw_dev *rtwdev, u8 pkt_id, u16 size, u8 location) { + struct rtw_chip_info *chip = rtwdev->chip; u8 h2c_pkt[H2C_PKT_SIZE] = {0}; u16 total_size = H2C_PKT_HDR_SIZE + H2C_PKT_UPDATE_PKT_LEN; @@ -1653,6 +1656,7 @@ static void __rtw_fw_update_pkt(struct rtw_dev *rtwdev, u8 pkt_id, u16 size, UPDATE_PKT_SET_LOCATION(h2c_pkt, location); /* include txdesc size */ + size += chip->tx_pkt_desc_sz; UPDATE_PKT_SET_SIZE(h2c_pkt, size); rtw_fw_send_h2c_packet(rtwdev, h2c_pkt); @@ -1662,7 +1666,7 @@ void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev, struct cfg80211_ssid *ssid) { u8 loc; - u32 size; + u16 size; loc = rtw_get_rsvd_page_probe_req_location(rtwdev, ssid); if (!loc) { diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index a8a7162fbe64..64dcde35a021 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -99,7 +99,7 @@ enum rtw_beacon_filter_offload_mode { BCN_FILTER_OFFLOAD_MODE_2, BCN_FILTER_OFFLOAD_MODE_3, - BCN_FILTER_OFFLOAD_MODE_DEFAULT = BCN_FILTER_OFFLOAD_MODE_1, + BCN_FILTER_OFFLOAD_MODE_DEFAULT = BCN_FILTER_OFFLOAD_MODE_0, }; struct rtw_coex_info_req { @@ -147,6 +147,7 @@ struct rtw_rsvd_page { u8 page; bool add_txdesc; struct cfg80211_ssid *ssid; + u16 probe_req_size; }; enum rtw_keep_alive_pkt_type { diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index c6364837e83b..6bb55e663fc3 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1338,6 +1338,8 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, if (rtw_chip_has_rx_ldpc(rtwdev)) ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING; + if (rtw_chip_has_tx_stbc(rtwdev)) + ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; if (efuse->hw_cap.bw & BIT(RTW_CHANNEL_WIDTH_40)) ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index e5af375b3dd0..56812127a053 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1146,6 +1146,7 @@ struct rtw_chip_info { u8 txgi_factor; bool is_pwr_by_rate_dec; bool rx_ldpc; + bool tx_stbc; u8 max_power_index; u16 fw_fifo_addr[RTW_FW_FIFO_MAX]; @@ -1959,6 +1960,11 @@ static inline bool rtw_chip_has_rx_ldpc(struct rtw_dev *rtwdev) return rtwdev->chip->rx_ldpc; } +static inline bool rtw_chip_has_tx_stbc(struct rtw_dev *rtwdev) +{ + return rtwdev->chip->tx_stbc; +} + static inline void rtw_release_macid(struct rtw_dev *rtwdev, u8 mac_id) { clear_bit(mac_id, rtwdev->mac_id_map); diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index e7d17ab8f113..a7a6ebfaa203 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -268,11 +268,6 @@ static int rtw_pci_init_rx_ring(struct rtw_dev *rtwdev, int i, allocated; int ret = 0; - if (len > TRX_BD_IDX_MASK) { - rtw_err(rtwdev, "len %d exceeds maximum RX entries\n", len); - return -EINVAL; - } - head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL); if (!head) { rtw_err(rtwdev, "failed to allocate rx ring\n"); @@ -1359,6 +1354,25 @@ static void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable) rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value); } +static void rtw_pci_clkreq_pad_low(struct rtw_dev *rtwdev, bool enable) +{ + u8 value; + int ret; + + ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value); + if (ret) { + rtw_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret); + return; + } + + if (enable) + value &= ~BIT_CLKREQ_N_PAD; + else + value |= BIT_CLKREQ_N_PAD; + + rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value); +} + static void rtw_pci_aspm_set(struct rtw_dev *rtwdev, bool enable) { u8 value; @@ -1500,11 +1514,25 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) static int __maybe_unused rtw_pci_suspend(struct device *dev) { + struct ieee80211_hw *hw = dev_get_drvdata(dev); + struct rtw_dev *rtwdev = hw->priv; + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; + + if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6) + rtw_pci_clkreq_pad_low(rtwdev, true); return 0; } static int __maybe_unused rtw_pci_resume(struct device *dev) { + struct ieee80211_hw *hw = dev_get_drvdata(dev); + struct rtw_dev *rtwdev = hw->priv; + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; + + if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6) + rtw_pci_clkreq_pad_low(rtwdev, false); return 0; } @@ -1701,6 +1729,15 @@ static const struct dmi_system_id rtw88_pci_quirks[] = { }, .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM), }, + { + .callback = disable_pci_caps, + .ident = "HP HP Pavilion Laptop 14-ce0xxx", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Laptop 14-ce0xxx"), + }, + .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM), + }, {} }; diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h index 0ffae887527a..66f78eb7757c 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.h +++ b/drivers/net/wireless/realtek/rtw88/pci.h @@ -37,6 +37,7 @@ #define RTK_PCIE_LINK_CFG 0x0719 #define BIT_CLKREQ_SW_EN BIT(4) #define BIT_L1_SW_EN BIT(3) +#define BIT_CLKREQ_N_PAD BIT(0) #define RTK_PCIE_CLKDLY_CTRL 0x0725 #define BIT_PCI_BCNQ_FLAG BIT(4) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 8bf3cd3a3678..f3ad079967a6 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -5288,6 +5288,7 @@ struct rtw_chip_info rtw8822c_hw_spec = { .bfer_su_max_num = 2, .bfer_mu_max_num = 1, .rx_ldpc = true, + .tx_stbc = true, #ifdef CONFIG_PM .wow_fw_name = "rtw88/rtw8822c_wow_fw.bin", diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 0193708fc013..3a101aa139ed 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -162,7 +162,7 @@ void rtw_tx_report_purge_timer(struct timer_list *t) if (skb_queue_len(&tx_report->queue) == 0) return; - rtw_dbg(rtwdev, RTW_DBG_TX, "purge skb(s) not reported by firmware\n"); + rtw_warn(rtwdev, "failed to get tx report from firmware\n"); spin_lock_irqsave(&tx_report->q_lock, flags); skb_queue_purge(&tx_report->queue); diff --git a/drivers/net/wireless/realtek/rtw88/wow.c b/drivers/net/wireless/realtek/rtw88/wow.c index fc9544f4e5e4..89dc595094d5 100644 --- a/drivers/net/wireless/realtek/rtw88/wow.c +++ b/drivers/net/wireless/realtek/rtw88/wow.c @@ -12,26 +12,54 @@ static void rtw_wow_show_wakeup_reason(struct rtw_dev *rtwdev) { + struct cfg80211_wowlan_nd_info nd_info; + struct cfg80211_wowlan_wakeup wakeup = { + .pattern_idx = -1, + }; u8 reason; reason = rtw_read8(rtwdev, REG_WOWLAN_WAKE_REASON); - if (reason == RTW_WOW_RSN_RX_DEAUTH) + switch (reason) { + case RTW_WOW_RSN_RX_DEAUTH: + wakeup.disconnect = true; rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx deauth\n"); - else if (reason == RTW_WOW_RSN_DISCONNECT) + break; + case RTW_WOW_RSN_DISCONNECT: + wakeup.disconnect = true; rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: AP is off\n"); - else if (reason == RTW_WOW_RSN_RX_MAGIC_PKT) + break; + case RTW_WOW_RSN_RX_MAGIC_PKT: + wakeup.magic_pkt = true; rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx magic packet\n"); - else if (reason == RTW_WOW_RSN_RX_GTK_REKEY) + break; + case RTW_WOW_RSN_RX_GTK_REKEY: + wakeup.gtk_rekey_failure = true; rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx gtk rekey\n"); - else if (reason == RTW_WOW_RSN_RX_PTK_REKEY) - rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx ptk rekey\n"); - else if (reason == RTW_WOW_RSN_RX_PATTERN_MATCH) + break; + case RTW_WOW_RSN_RX_PATTERN_MATCH: + /* Current firmware and driver don't report pattern index + * Use pattern_idx to 0 defaultly. + */ + wakeup.pattern_idx = 0; rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx pattern match packet\n"); - else if (reason == RTW_WOW_RSN_RX_NLO) + break; + case RTW_WOW_RSN_RX_NLO: + /* Current firmware and driver don't report ssid index. + * Use 0 for n_matches based on its comment. + */ + nd_info.n_matches = 0; + wakeup.net_detect = &nd_info; rtw_dbg(rtwdev, RTW_DBG_WOW, "Rx NLO\n"); - else + break; + default: rtw_warn(rtwdev, "Unknown wakeup reason %x\n", reason); + ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL, + GFP_KERNEL); + return; + } + ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup, + GFP_KERNEL); } static void rtw_wow_pattern_write_cam(struct rtw_dev *rtwdev, u8 addr, @@ -283,15 +311,26 @@ static void rtw_wow_rx_dma_start(struct rtw_dev *rtwdev) static int rtw_wow_check_fw_status(struct rtw_dev *rtwdev, bool wow_enable) { - /* wait 100ms for wow firmware to finish work */ - msleep(100); + int ret; + u8 check; + u32 check_dis; if (wow_enable) { - if (rtw_read8(rtwdev, REG_WOWLAN_WAKE_REASON)) + ret = read_poll_timeout(rtw_read8, check, !check, 1000, + 100000, true, rtwdev, + REG_WOWLAN_WAKE_REASON); + if (ret) goto wow_fail; } else { - if (rtw_read32_mask(rtwdev, REG_FE1IMR, BIT_FS_RXDONE) || - rtw_read32_mask(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE)) + ret = read_poll_timeout(rtw_read32_mask, check_dis, + !check_dis, 1000, 100000, true, rtwdev, + REG_FE1IMR, BIT_FS_RXDONE); + if (ret) + goto wow_fail; + ret = read_poll_timeout(rtw_read32_mask, check_dis, + !check_dis, 1000, 100000, false, rtwdev, + REG_RXPKT_NUM, BIT_RW_RELEASE); + if (ret) goto wow_fail; } @@ -432,37 +471,31 @@ static void rtw_wow_fw_media_status(struct rtw_dev *rtwdev, bool connect) rtw_iterate_stas_atomic(rtwdev, rtw_wow_fw_media_status_iter, &data); } -static void rtw_wow_config_pno_rsvd_page(struct rtw_dev *rtwdev, - struct rtw_vif *rtwvif) +static int rtw_wow_config_wow_fw_rsvd_page(struct rtw_dev *rtwdev) { - rtw_add_rsvd_page_pno(rtwdev, rtwvif); -} - -static void rtw_wow_config_linked_rsvd_page(struct rtw_dev *rtwdev, - struct rtw_vif *rtwvif) -{ - rtw_add_rsvd_page_sta(rtwdev, rtwvif); -} + struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw_vif *rtwvif = (struct rtw_vif *)wow_vif->drv_priv; -static void rtw_wow_config_rsvd_page(struct rtw_dev *rtwdev, - struct rtw_vif *rtwvif) -{ rtw_remove_rsvd_page(rtwdev, rtwvif); - if (rtw_wow_mgd_linked(rtwdev)) { - rtw_wow_config_linked_rsvd_page(rtwdev, rtwvif); - } else if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags) && - rtw_wow_no_link(rtwdev)) { - rtw_wow_config_pno_rsvd_page(rtwdev, rtwvif); - } + if (rtw_wow_no_link(rtwdev)) + rtw_add_rsvd_page_pno(rtwdev, rtwvif); + else + rtw_add_rsvd_page_sta(rtwdev, rtwvif); + + return rtw_fw_download_rsvd_page(rtwdev); } -static int rtw_wow_dl_fw_rsvd_page(struct rtw_dev *rtwdev) +static int rtw_wow_config_normal_fw_rsvd_page(struct rtw_dev *rtwdev) { struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; struct rtw_vif *rtwvif = (struct rtw_vif *)wow_vif->drv_priv; - rtw_wow_config_rsvd_page(rtwdev, rtwvif); + rtw_remove_rsvd_page(rtwdev, rtwvif); + rtw_add_rsvd_page_sta(rtwdev, rtwvif); + + if (rtw_wow_no_link(rtwdev)) + return 0; return rtw_fw_download_rsvd_page(rtwdev); } @@ -660,7 +693,7 @@ static int rtw_wow_enable(struct rtw_dev *rtwdev) set_bit(RTW_FLAG_WOWLAN, rtwdev->flags); - ret = rtw_wow_dl_fw_rsvd_page(rtwdev); + ret = rtw_wow_config_wow_fw_rsvd_page(rtwdev); if (ret) { rtw_err(rtwdev, "failed to download wowlan rsvd page\n"); goto error; @@ -733,7 +766,7 @@ static int rtw_wow_disable(struct rtw_dev *rtwdev) goto out; } - ret = rtw_wow_dl_fw_rsvd_page(rtwdev); + ret = rtw_wow_config_normal_fw_rsvd_page(rtwdev); if (ret) rtw_err(rtwdev, "failed to download normal rsvd page\n"); diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c index 24a417ea2ae7..bf22fd948276 100644 --- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -117,7 +117,7 @@ static int rsi_stats_read(struct seq_file *seq, void *data) { struct rsi_common *common = seq->private; - unsigned char fsm_state[][32] = { + static const unsigned char fsm_state[][32] = { "FSM_FW_NOT_LOADED", "FSM_CARD_NOT_READY", "FSM_COMMON_DEV_PARAMS_SENT", diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 99b21a2c8386..f4a26f16f00f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -1038,8 +1038,10 @@ static int rsi_load_9116_firmware(struct rsi_hw *adapter) } ta_firmware = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!ta_firmware) + if (!ta_firmware) { + status = -ENOMEM; goto fail_release_fw; + } fw_p = ta_firmware; instructions_sz = fw_entry->size; rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", instructions_sz); diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 3fbe2a3c1455..416976f09888 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -816,6 +816,7 @@ static int rsi_probe(struct usb_interface *pfunction, } else { rsi_dbg(ERR_ZONE, "%s: Unsupported RSI device id 0x%x\n", __func__, id->idProduct); + status = -ENODEV; goto err1; } |