diff options
author | Jakub Kicinski | 2023-01-23 21:27:30 -0800 |
---|---|---|
committer | Jakub Kicinski | 2023-01-23 21:27:31 -0800 |
commit | 62be69397e53ab14f607698bb41343ce576713e8 (patch) | |
tree | a98a6863f9d2e917abf045ee30145895166b7f7a | |
parent | 306f208259ff7a89c022f1e5f5d2144b0ccb236c (diff) | |
parent | 4ca69027691a0039279b64cfa0aa511d9c9fde59 (diff) |
Merge tag 'wireless-next-2023-01-23' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Kalle Valo says:
====================
wireless-next patches for v6.3
First set of patches for v6.3. The most important change here is that
the old Wireless Extension user space interface is not supported on
Wi-Fi 7 devices at all. We also added a warning if anyone with modern
drivers (ie. cfg80211 and mac80211 drivers) tries to use Wireless
Extensions, everyone should switch to using nl80211 interface instead.
Static WEP support is removed, there wasn't any driver using that
anyway so there's no user impact. Otherwise it's smaller features and
fixes as usual.
Note: As mt76 had tricky conflicts due to the fixes in wireless tree,
we decided to merge wireless into wireless-next to solve them easily.
There should not be any merge problems anymore.
Major changes:
cfg80211
- remove never used static WEP support
- warn if Wireless Extention interface is used with cfg80211/mac80211 drivers
- stop supporting Wireless Extensions with Wi-Fi 7 devices
- support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate reporting
rfkill
- add GPIO DT support
bitfield
- add FIELD_PREP_CONST()
mt76
- per-PHY LED support
rtw89
- support new Bluetooth co-existance version
rtl8xxxu
- support RTL8188EU
* tag 'wireless-next-2023-01-23' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (123 commits)
wifi: wireless: deny wireless extensions on MLO-capable devices
wifi: wireless: warn on most wireless extension usage
wifi: mac80211: drop extra 'e' from ieeee80211... name
wifi: cfg80211: Deduplicate certificate loading
bitfield: add FIELD_PREP_CONST()
wifi: mac80211: add kernel-doc for EHT structure
mac80211: support minimal EHT rate reporting on RX
wifi: mac80211: Add HE MU-MIMO related flags in ieee80211_bss_conf
wifi: mac80211: Add VHT MU-MIMO related flags in ieee80211_bss_conf
wifi: cfg80211: Use MLD address to indicate MLD STA disconnection
wifi: cfg80211: Support 32 bytes KCK key in GTK rekey offload
wifi: cfg80211: Fix extended KCK key length check in nl80211_set_rekey_data()
wifi: cfg80211: remove support for static WEP
wifi: rtl8xxxu: Dump the efuse only for untested devices
wifi: rtl8xxxu: Print the ROM version too
wifi: rtw88: Use non-atomic sta iterator in rtw_ra_mask_info_update()
wifi: rtw88: Use rtw_iterate_vifs() for rtw_vif_watch_dog_iter()
wifi: rtw88: Move register access from rtw_bf_assoc() outside the RCU
wifi: rtl8xxxu: Use a longer retry limit of 48
wifi: rtl8xxxu: Report the RSSI to the firmware
...
====================
Link: https://lore.kernel.org/r/20230123103338.330CBC433EF@smtp.kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
109 files changed, 5079 insertions, 1341 deletions
diff --git a/Documentation/devicetree/bindings/net/rfkill-gpio.yaml b/Documentation/devicetree/bindings/net/rfkill-gpio.yaml new file mode 100644 index 000000000000..9630c8466fac --- /dev/null +++ b/Documentation/devicetree/bindings/net/rfkill-gpio.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/rfkill-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPIO controlled rfkill switch + +maintainers: + - Johannes Berg <johannes@sipsolutions.net> + - Philipp Zabel <p.zabel@pengutronix.de> + +properties: + compatible: + const: rfkill-gpio + + label: + description: rfkill switch name, defaults to node name + + radio-type: + description: rfkill radio type + enum: + - bluetooth + - fm + - gps + - nfc + - ultrawideband + - wimax + - wlan + - wwan + + shutdown-gpios: + maxItems: 1 + +required: + - compatible + - radio-type + - shutdown-gpios + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + rfkill { + compatible = "rfkill-gpio"; + label = "rfkill-pcie-wlan"; + radio-type = "wlan"; + shutdown-gpios = <&gpio2 25 GPIO_ACTIVE_HIGH>; + }; diff --git a/crypto/asymmetric_keys/x509_loader.c b/crypto/asymmetric_keys/x509_loader.c index 1bc169dee22e..a41741326998 100644 --- a/crypto/asymmetric_keys/x509_loader.c +++ b/crypto/asymmetric_keys/x509_loader.c @@ -55,3 +55,4 @@ dodgy_cert: pr_err("Problem parsing in-kernel X.509 certificate list\n"); return 0; } +EXPORT_SYMBOL_GPL(x509_load_certificate_list); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 2a8a3e3dcff6..b3a7d7bfe17c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -3853,8 +3853,8 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk switch (ev->evt_type) { case WMI_BSS_COLOR_COLLISION_DETECTION: - ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap, - GFP_KERNEL); + ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap, + GFP_KERNEL); ath11k_dbg(ab, ATH11K_DBG_WMI, "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n", ev->vdev_id, ev->evt_type, ev->obss_color_bitmap); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 4a309e5a5707..f235beaddddb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -299,6 +299,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) err); goto done; } + buf[sizeof(buf) - 1] = '\0'; ptr = (char *)buf; strsep(&ptr, "\n"); @@ -319,15 +320,17 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) if (err) { brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err); } else { + buf[sizeof(buf) - 1] = '\0'; clmver = (char *)buf; - /* store CLM version for adding it to revinfo debugfs file */ - memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver)); /* Replace all newline/linefeed characters with space * character */ strreplace(clmver, '\n', ' '); + /* store CLM version for adding it to revinfo debugfs file */ + memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver)); + brcmf_dbg(INFO, "CLM version = %s\n", clmver); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 83ea251cfcec..f599d5f896e8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -336,6 +336,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, bphy_err(drvr, "%s: failed to expand headroom\n", brcmf_ifname(ifp)); atomic_inc(&drvr->bus_if->stats.pktcow_failed); + dev_kfree_skb(skb); goto done; } } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index cec53f934940..45fbcbdc7d9e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -347,8 +347,11 @@ brcmf_msgbuf_alloc_pktid(struct device *dev, count++; } while (count < pktids->array_size); - if (count == pktids->array_size) + if (count == pktids->array_size) { + dma_unmap_single(dev, *physaddr, skb->len - data_offset, + pktids->direction); return -ENOMEM; + } array[*idx].data_offset = data_offset; array[*idx].physaddr = *physaddr; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index ca802af8cddc..d382f2017325 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -3427,7 +3427,7 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv, dma_unmap_single(&priv->pci_dev->dev, rxq->pool[i].dma_addr, IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); - dev_kfree_skb(rxq->pool[i].skb); + dev_kfree_skb_irq(rxq->pool[i].skb); rxq->pool[i].skb = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); @@ -11383,9 +11383,14 @@ static int ipw_wdev_init(struct net_device *dev) set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); /* With that information in place, we can now register the wiphy... */ - if (wiphy_register(wdev->wiphy)) - rc = -EIO; + rc = wiphy_register(wdev->wiphy); + if (rc) + goto out; + + return 0; out: + kfree(priv->ieee->a_band.channels); + kfree(priv->ieee->bg_band.channels); return rc; } diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 341c17fe2af4..96002121bb8b 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5174,7 +5174,7 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) memset(&il->current_ht_config, 0, sizeof(struct il_ht_config)); /* new association get rid of ibss beacon skb */ - dev_kfree_skb(il->beacon_skb); + dev_consume_skb_irq(il->beacon_skb); il->beacon_skb = NULL; il->timestamp = 0; @@ -5293,7 +5293,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } spin_lock_irqsave(&il->lock, flags); - dev_kfree_skb(il->beacon_skb); + dev_consume_skb_irq(il->beacon_skb); il->beacon_skb = skb; timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c index 0aea35c9c11c..4fcca08e50de 100644 --- a/drivers/net/wireless/intersil/orinoco/hw.c +++ b/drivers/net/wireless/intersil/orinoco/hw.c @@ -931,6 +931,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFAUTHENTICATION_AGERE, auth_flag); + if (err) + return err; } err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPENABLED_AGERE, diff --git a/drivers/net/wireless/marvell/libertas/cmdresp.c b/drivers/net/wireless/marvell/libertas/cmdresp.c index cb515c5584c1..74cb7551f427 100644 --- a/drivers/net/wireless/marvell/libertas/cmdresp.c +++ b/drivers/net/wireless/marvell/libertas/cmdresp.c @@ -48,7 +48,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv, /* Free Tx and Rx packets */ spin_lock_irqsave(&priv->driver_lock, flags); - kfree_skb(priv->currenttxskb); + dev_kfree_skb_irq(priv->currenttxskb); priv->currenttxskb = NULL; priv->tx_pending_len = 0; spin_unlock_irqrestore(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index 32fdc4150b60..2240b4db8c03 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -637,7 +637,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN); memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN, priv->resp_len[i]); - kfree_skb(skb); + dev_kfree_skb_irq(skb); lbs_notify_command_response(priv, i); spin_unlock_irqrestore(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c index 8f5220cee112..78e8b5aecec0 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -216,7 +216,7 @@ int lbs_stop_iface(struct lbs_private *priv) spin_lock_irqsave(&priv->driver_lock, flags); priv->iface_running = false; - kfree_skb(priv->currenttxskb); + dev_kfree_skb_irq(priv->currenttxskb); priv->currenttxskb = NULL; priv->tx_pending_len = 0; spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -869,6 +869,7 @@ static int lbs_init_adapter(struct lbs_private *priv) ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL); if (ret) { pr_err("Out of memory allocating event FIFO buffer\n"); + lbs_free_cmd_buffer(priv); goto out; } diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c index 75b5319d033f..1750f5e93de2 100644 --- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c +++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c @@ -613,7 +613,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, spin_lock_irqsave(&priv->driver_lock, flags); memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN, recvlength - MESSAGE_HEADER_LEN); - kfree_skb(skb); + dev_kfree_skb_irq(skb); lbtf_cmd_response_rx(priv); spin_unlock_irqrestore(&priv->driver_lock, flags); } diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index 11b0b3d62f29..57fbcc83e074 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -112,7 +112,7 @@ mt76_register_debugfs_fops(struct mt76_phy *phy, if (!dir) return NULL; - debugfs_create_u8("led_pin", 0600, dir, &dev->led_pin); + debugfs_create_u8("led_pin", 0600, dir, &phy->leds.pin); debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg); debugfs_create_file_unsafe("regval", 0600, dir, dev, fops); debugfs_create_file_unsafe("napi_threaded", 0600, dir, dev, diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 06161815c180..8de9376765c0 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -582,23 +582,9 @@ free_skb: return ret; } -static struct page_frag_cache * -mt76_dma_rx_get_frag_cache(struct mt76_dev *dev, struct mt76_queue *q) -{ - struct page_frag_cache *rx_page = &q->rx_page; - -#ifdef CONFIG_NET_MEDIATEK_SOC_WED - if ((q->flags & MT_QFLAG_WED) && - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) - rx_page = &dev->mmio.wed.rx_buf_ring.rx_page; -#endif - return rx_page; -} - static int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) { - struct page_frag_cache *rx_page = mt76_dma_rx_get_frag_cache(dev, q); int len = SKB_WITH_OVERHEAD(q->buf_size); int frames = 0, offset = q->buf_offset; dma_addr_t addr; @@ -612,7 +598,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) struct mt76_queue_buf qbuf; void *buf = NULL; - buf = page_frag_alloc(rx_page, q->buf_size, GFP_ATOMIC); + buf = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC); if (!buf) break; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index fc608b369b3c..7fe7f68acc24 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -192,42 +192,48 @@ static const struct cfg80211_sar_capa mt76_sar_capa = { .freq_ranges = &mt76_sar_freq_ranges[0], }; -static int mt76_led_init(struct mt76_dev *dev) +static int mt76_led_init(struct mt76_phy *phy) { - struct device_node *np = dev->dev->of_node; - struct ieee80211_hw *hw = dev->hw; - int led_pin; + struct mt76_dev *dev = phy->dev; + struct ieee80211_hw *hw = phy->hw; - if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) + if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) return 0; - snprintf(dev->led_name, sizeof(dev->led_name), - "mt76-%s", wiphy_name(hw->wiphy)); + snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s", + wiphy_name(hw->wiphy)); - dev->led_cdev.name = dev->led_name; - dev->led_cdev.default_trigger = + phy->leds.cdev.name = phy->leds.name; + phy->leds.cdev.default_trigger = ieee80211_create_tpt_led_trigger(hw, IEEE80211_TPT_LEDTRIG_FL_RADIO, mt76_tpt_blink, ARRAY_SIZE(mt76_tpt_blink)); - np = of_get_child_by_name(np, "led"); - if (np) { - if (!of_property_read_u32(np, "led-sources", &led_pin)) - dev->led_pin = led_pin; - dev->led_al = of_property_read_bool(np, "led-active-low"); - of_node_put(np); + if (phy == &dev->phy) { + struct device_node *np = dev->dev->of_node; + + np = of_get_child_by_name(np, "led"); + if (np) { + int led_pin; + + if (!of_property_read_u32(np, "led-sources", &led_pin)) + phy->leds.pin = led_pin; + phy->leds.al = of_property_read_bool(np, + "led-active-low"); + of_node_put(np); + } } - return led_classdev_register(dev->dev, &dev->led_cdev); + return led_classdev_register(dev->dev, &phy->leds.cdev); } -static void mt76_led_cleanup(struct mt76_dev *dev) +static void mt76_led_cleanup(struct mt76_phy *phy) { - if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) + if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) return; - led_classdev_unregister(&dev->led_cdev); + led_classdev_unregister(&phy->leds.cdev); } static void mt76_init_stream_cap(struct mt76_phy *phy, @@ -517,6 +523,12 @@ int mt76_register_phy(struct mt76_phy *phy, bool vht, return ret; } + if (IS_ENABLED(CONFIG_MT76_LEDS)) { + ret = mt76_led_init(phy); + if (ret) + return ret; + } + wiphy_read_of_freq_limits(phy->hw->wiphy); mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); @@ -536,6 +548,8 @@ void mt76_unregister_phy(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; + if (IS_ENABLED(CONFIG_MT76_LEDS)) + mt76_led_cleanup(phy); mt76_tx_status_check(dev, true); ieee80211_unregister_hw(phy->hw); dev->phys[phy->band_idx] = NULL; @@ -653,7 +667,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); if (IS_ENABLED(CONFIG_MT76_LEDS)) { - ret = mt76_led_init(dev); + ret = mt76_led_init(phy); if (ret) return ret; } @@ -674,7 +688,7 @@ void mt76_unregister_device(struct mt76_dev *dev) struct ieee80211_hw *hw = dev->hw; if (IS_ENABLED(CONFIG_MT76_LEDS)) - mt76_led_cleanup(dev); + mt76_led_cleanup(&dev->phy); mt76_tx_status_check(dev, true); ieee80211_unregister_hw(hw); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 32a77a0ae9da..1037d23bc4d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -731,6 +731,13 @@ struct mt76_phy { } rx_amsdu[__MT_RXQ_MAX]; struct mt76_freq_range_power *frp; + + struct { + struct led_classdev cdev; + char name[32]; + bool al; + u8 pin; + } leds; }; struct mt76_dev { @@ -812,11 +819,6 @@ struct mt76_dev { u32 debugfs_reg; - struct led_classdev led_cdev; - char led_name[32]; - bool led_al; - u8 led_pin; - u8 csa_complete; u32 rxfilter; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index 031d39a48a55..9a2e632d577a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -330,10 +330,10 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; -static void mt7603_led_set_config(struct mt76_dev *mt76, u8 delay_on, +static void mt7603_led_set_config(struct mt76_phy *mphy, u8 delay_on, u8 delay_off) { - struct mt7603_dev *dev = container_of(mt76, struct mt7603_dev, + struct mt7603_dev *dev = container_of(mphy->dev, struct mt7603_dev, mt76); u32 val, addr; @@ -341,15 +341,15 @@ static void mt7603_led_set_config(struct mt76_dev *mt76, u8 delay_on, FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | FIELD_PREP(MT_LED_STATUS_ON, delay_on); - addr = mt7603_reg_map(dev, MT_LED_STATUS_0(mt76->led_pin)); + addr = mt7603_reg_map(dev, MT_LED_STATUS_0(mphy->leds.pin)); mt76_wr(dev, addr, val); - addr = mt7603_reg_map(dev, MT_LED_STATUS_1(mt76->led_pin)); + addr = mt7603_reg_map(dev, MT_LED_STATUS_1(mphy->leds.pin)); mt76_wr(dev, addr, val); - val = MT_LED_CTRL_REPLAY(mt76->led_pin) | - MT_LED_CTRL_KICK(mt76->led_pin); - if (mt76->led_al) - val |= MT_LED_CTRL_POLARITY(mt76->led_pin); + val = MT_LED_CTRL_REPLAY(mphy->leds.pin) | + MT_LED_CTRL_KICK(mphy->leds.pin); + if (mphy->leds.al) + val |= MT_LED_CTRL_POLARITY(mphy->leds.pin); addr = mt7603_reg_map(dev, MT_LED_CTRL); mt76_wr(dev, addr, val); } @@ -358,27 +358,27 @@ static int mt7603_led_set_blink(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { - struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, - led_cdev); + struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, + leds.cdev); u8 delta_on, delta_off; delta_off = max_t(u8, *delay_off / 10, 1); delta_on = max_t(u8, *delay_on / 10, 1); - mt7603_led_set_config(mt76, delta_on, delta_off); + mt7603_led_set_config(mphy, delta_on, delta_off); return 0; } static void mt7603_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, - led_cdev); + struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, + leds.cdev); if (!brightness) - mt7603_led_set_config(mt76, 0, 0xff); + mt7603_led_set_config(mphy, 0, 0xff); else - mt7603_led_set_config(mt76, 0xff, 0); + mt7603_led_set_config(mphy, 0xff, 0); } static u32 __mt7603_reg_addr(struct mt7603_dev *dev, u32 addr) @@ -535,8 +535,8 @@ int mt7603_register_device(struct mt7603_dev *dev) /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { - dev->mt76.led_cdev.brightness_set = mt7603_led_set_brightness; - dev->mt76.led_cdev.blink_set = mt7603_led_set_blink; + dev->mphy.leds.cdev.brightness_set = mt7603_led_set_brightness; + dev->mphy.leds.cdev.blink_set = mt7603_led_set_blink; } wiphy->reg_notifier = mt7603_regd_notifier; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 07a1fea94f66..5fa6f097ec30 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -443,6 +443,85 @@ mt7615_cap_dbdc_disable(struct mt7615_dev *dev) mt76_set_stream_caps(&dev->mphy, true); } +u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr) +{ + u32 base, offset; + + if (is_mt7663(&dev->mt76)) { + base = addr & MT7663_MCU_PCIE_REMAP_2_BASE; + offset = addr & MT7663_MCU_PCIE_REMAP_2_OFFSET; + } else { + base = addr & MT_MCU_PCIE_REMAP_2_BASE; + offset = addr & MT_MCU_PCIE_REMAP_2_OFFSET; + } + mt76_wr(dev, MT_MCU_PCIE_REMAP_2, base); + + return MT_PCIE_REMAP_BASE_2 + offset; +} +EXPORT_SYMBOL_GPL(mt7615_reg_map); + +static void +mt7615_led_set_config(struct led_classdev *led_cdev, + u8 delay_on, u8 delay_off) +{ + struct mt7615_dev *dev; + struct mt76_phy *mphy; + u32 val, addr; + u8 index; + + mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); + dev = container_of(mphy->dev, struct mt7615_dev, mt76); + + if (!mt76_connac_pm_ref(mphy, &dev->pm)) + return; + + val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | + FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | + FIELD_PREP(MT_LED_STATUS_ON, delay_on); + + index = dev->dbdc_support ? mphy->band_idx : mphy->leds.pin; + addr = mt7615_reg_map(dev, MT_LED_STATUS_0(index)); + mt76_wr(dev, addr, val); + addr = mt7615_reg_map(dev, MT_LED_STATUS_1(index)); + mt76_wr(dev, addr, val); + + val = MT_LED_CTRL_REPLAY(index) | MT_LED_CTRL_KICK(index); + if (dev->mphy.leds.al) + val |= MT_LED_CTRL_POLARITY(index); + if (mphy->band_idx) + val |= MT_LED_CTRL_BAND(index); + + addr = mt7615_reg_map(dev, MT_LED_CTRL); + mt76_wr(dev, addr, val); + + mt76_connac_pm_unref(mphy, &dev->pm); +} + +int mt7615_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + u8 delta_on, delta_off; + + delta_off = max_t(u8, *delay_off / 10, 1); + delta_on = max_t(u8, *delay_on / 10, 1); + + mt7615_led_set_config(led_cdev, delta_on, delta_off); + + return 0; +} +EXPORT_SYMBOL_GPL(mt7615_led_set_blink); + +void mt7615_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + if (!brightness) + mt7615_led_set_config(led_cdev, 0, 0xff); + else + mt7615_led_set_config(led_cdev, 0xff, 0); +} +EXPORT_SYMBOL_GPL(mt7615_led_set_brightness); + int mt7615_register_ext_phy(struct mt7615_dev *dev) { struct mt7615_phy *phy = mt7615_ext_phy(dev); @@ -497,6 +576,12 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) for (i = 0; i <= MT_TXQ_PSD ; i++) mphy->q_tx[i] = dev->mphy.q_tx[i]; + /* init led callbacks */ + if (IS_ENABLED(CONFIG_MT76_LEDS)) { + mphy->leds.cdev.brightness_set = mt7615_led_set_brightness; + mphy->leds.cdev.blink_set = mt7615_led_set_blink; + } + ret = mt76_register_phy(mphy, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index a784f9d9e935..83173efb56dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -63,22 +63,6 @@ const u32 mt7663e_reg_map[] = { [MT_EFUSE_ADDR_BASE] = 0x78011000, }; -u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr) -{ - u32 base, offset; - - if (is_mt7663(&dev->mt76)) { - base = addr & MT7663_MCU_PCIE_REMAP_2_BASE; - offset = addr & MT7663_MCU_PCIE_REMAP_2_OFFSET; - } else { - base = addr & MT_MCU_PCIE_REMAP_2_BASE; - offset = addr & MT_MCU_PCIE_REMAP_2_OFFSET; - } - mt76_wr(dev, MT_MCU_PCIE_REMAP_2, base); - - return MT_PCIE_REMAP_BASE_2 + offset; -} - static void mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 087d4886162e..43591b4c1d9a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -376,6 +376,12 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map); u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr); +u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr); +int mt7615_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off); +void mt7615_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness); void mt7615_init_device(struct mt7615_dev *dev); int mt7615_register_device(struct mt7615_dev *dev); void mt7615_unregister_device(struct mt7615_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index 87b4aa52ee0f..0680e002b981 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -66,64 +66,6 @@ static int mt7615_init_hardware(struct mt7615_dev *dev) return 0; } -static void -mt7615_led_set_config(struct led_classdev *led_cdev, - u8 delay_on, u8 delay_off) -{ - struct mt7615_dev *dev; - struct mt76_dev *mt76; - u32 val, addr; - - mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); - dev = container_of(mt76, struct mt7615_dev, mt76); - - if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) - return; - - val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | - FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | - FIELD_PREP(MT_LED_STATUS_ON, delay_on); - - addr = mt7615_reg_map(dev, MT_LED_STATUS_0(mt76->led_pin)); - mt76_wr(dev, addr, val); - addr = mt7615_reg_map(dev, MT_LED_STATUS_1(mt76->led_pin)); - mt76_wr(dev, addr, val); - - val = MT_LED_CTRL_REPLAY(mt76->led_pin) | - MT_LED_CTRL_KICK(mt76->led_pin); - if (mt76->led_al) - val |= MT_LED_CTRL_POLARITY(mt76->led_pin); - addr = mt7615_reg_map(dev, MT_LED_CTRL); - mt76_wr(dev, addr, val); - - mt76_connac_pm_unref(&dev->mphy, &dev->pm); -} - -static int -mt7615_led_set_blink(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off) -{ - u8 delta_on, delta_off; - - delta_off = max_t(u8, *delay_off / 10, 1); - delta_on = max_t(u8, *delay_on / 10, 1); - - mt7615_led_set_config(led_cdev, delta_on, delta_off); - - return 0; -} - -static void -mt7615_led_set_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - if (!brightness) - mt7615_led_set_config(led_cdev, 0, 0xff); - else - mt7615_led_set_config(led_cdev, 0xff, 0); -} - int mt7615_register_device(struct mt7615_dev *dev) { int ret; @@ -133,8 +75,8 @@ int mt7615_register_device(struct mt7615_dev *dev) /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { - dev->mt76.led_cdev.brightness_set = mt7615_led_set_brightness; - dev->mt76.led_cdev.blink_set = mt7615_led_set_blink; + dev->mphy.leds.cdev.brightness_set = mt7615_led_set_brightness; + dev->mphy.leds.cdev.blink_set = mt7615_led_set_blink; } ret = mt7622_wmac_init(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index fa1b9b26b399..7cecb22c569e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -544,6 +544,7 @@ enum mt7615_reg_base { #define MT_LED_CTRL_POLARITY(_n) BIT(1 + (8 * (_n))) #define MT_LED_CTRL_TX_BLINK_MODE(_n) BIT(2 + (8 * (_n))) #define MT_LED_CTRL_TX_MANUAL_BLINK(_n) BIT(3 + (8 * (_n))) +#define MT_LED_CTRL_BAND(_n) BIT(4 + (8 * (_n))) #define MT_LED_CTRL_TX_OVER_BLINK(_n) BIT(5 + (8 * (_n))) #define MT_LED_CTRL_KICK(_n) BIT(7 + (8 * (_n))) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index fd60123fb284..c8d0c84e688b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -930,7 +930,7 @@ int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif, ether_addr_copy(hdr.addr4, eth_hdr->h_source); break; default: - break; + return -EINVAL; } skb_pull(skb, hdr_offset + sizeof(struct ethhdr) - 2); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 6c6c8ada7943..d543ef3de65b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -642,7 +642,12 @@ mt76x0_phy_get_target_power(struct mt76x02_dev *dev, u8 tx_mode, if (tx_rate > 9) return -EINVAL; - *target_power = cur_power + dev->rate_power.vht[tx_rate]; + *target_power = cur_power; + if (tx_rate > 7) + *target_power += dev->rate_power.vht[tx_rate - 8]; + else + *target_power += dev->rate_power.ht[tx_rate]; + *target_pa_power = mt76x0_phy_get_rf_pa_mode(dev, 1, tx_rate); break; default: diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 604ddcc21123..7451a63206a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -87,10 +87,9 @@ static const struct ieee80211_iface_combination mt76x02u_if_comb[] = { }; static void -mt76x02_led_set_config(struct mt76_dev *mdev, u8 delay_on, - u8 delay_off) +mt76x02_led_set_config(struct mt76_phy *mphy, u8 delay_on, u8 delay_off) { - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, + struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, mt76); u32 val; @@ -98,13 +97,13 @@ mt76x02_led_set_config(struct mt76_dev *mdev, u8 delay_on, FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | FIELD_PREP(MT_LED_STATUS_ON, delay_on); - mt76_wr(dev, MT_LED_S0(mdev->led_pin), val); - mt76_wr(dev, MT_LED_S1(mdev->led_pin), val); + mt76_wr(dev, MT_LED_S0(mphy->leds.pin), val); + mt76_wr(dev, MT_LED_S1(mphy->leds.pin), val); - val = MT_LED_CTRL_REPLAY(mdev->led_pin) | - MT_LED_CTRL_KICK(mdev->led_pin); - if (mdev->led_al) - val |= MT_LED_CTRL_POLARITY(mdev->led_pin); + val = MT_LED_CTRL_REPLAY(mphy->leds.pin) | + MT_LED_CTRL_KICK(mphy->leds.pin); + if (mphy->leds.al) + val |= MT_LED_CTRL_POLARITY(mphy->leds.pin); mt76_wr(dev, MT_LED_CTRL, val); } @@ -113,14 +112,14 @@ mt76x02_led_set_blink(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { - struct mt76_dev *mdev = container_of(led_cdev, struct mt76_dev, - led_cdev); + struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, + leds.cdev); u8 delta_on, delta_off; delta_off = max_t(u8, *delay_off / 10, 1); delta_on = max_t(u8, *delay_on / 10, 1); - mt76x02_led_set_config(mdev, delta_on, delta_off); + mt76x02_led_set_config(mphy, delta_on, delta_off); return 0; } @@ -129,13 +128,13 @@ static void mt76x02_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct mt76_dev *mdev = container_of(led_cdev, struct mt76_dev, - led_cdev); + struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, + leds.cdev); if (!brightness) - mt76x02_led_set_config(mdev, 0, 0xff); + mt76x02_led_set_config(mphy, 0, 0xff); else - mt76x02_led_set_config(mdev, 0xff, 0); + mt76x02_led_set_config(mphy, 0xff, 0); } int mt76x02_init_device(struct mt76x02_dev *dev) @@ -167,9 +166,9 @@ int mt76x02_init_device(struct mt76x02_dev *dev) /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { - dev->mt76.led_cdev.brightness_set = + dev->mphy.leds.cdev.brightness_set = mt76x02_led_set_brightness; - dev->mt76.led_cdev.blink_set = mt76x02_led_set_blink; + dev->mphy.leds.cdev.blink_set = mt76x02_led_set_blink; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index fb46c2c1784f..5a46813a59ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -811,7 +811,7 @@ mt7915_hw_queue_read(struct seq_file *s, u32 size, if (val & BIT(map[i].index)) continue; - ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24); + ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24); mt76_wr(dev, MT_FL_Q0_CTRL, ctrl); head = mt76_get_field(dev, MT_FL_Q2_CTRL, @@ -996,7 +996,7 @@ mt7915_rate_txpower_get(struct file *file, char __user *user_buf, ret = mt7915_mcu_get_txpower_sku(phy, txpwr, sizeof(txpwr)); if (ret) - return ret; + goto out; /* Txpower propagation path: TMAC -> TXV -> BBP */ len += scnprintf(buf + len, sz - len, @@ -1047,6 +1047,8 @@ mt7915_rate_txpower_get(struct file *file, char __user *user_buf, mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER)); ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + +out: kfree(buf); return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 59069fb86414..24efa280dd86 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -110,18 +110,23 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev) } else { u8 free_block_num; u32 block_num, i; + u32 eeprom_blk_size = MT7915_EEPROM_BLOCK_SIZE; - mt7915_mcu_get_eeprom_free_block(dev, &free_block_num); - /* efuse info not enough */ + ret = mt7915_mcu_get_eeprom_free_block(dev, &free_block_num); + if (ret < 0) + return ret; + + /* efuse info isn't enough */ if (free_block_num >= 29) return -EINVAL; /* read eeprom data from efuse */ - block_num = DIV_ROUND_UP(eeprom_size, - MT7915_EEPROM_BLOCK_SIZE); - for (i = 0; i < block_num; i++) - mt7915_mcu_get_eeprom(dev, - i * MT7915_EEPROM_BLOCK_SIZE); + block_num = DIV_ROUND_UP(eeprom_size, eeprom_blk_size); + for (i = 0; i < block_num; i++) { + ret = mt7915_mcu_get_eeprom(dev, i * eeprom_blk_size); + if (ret < 0) + return ret; + } } return mt7915_check_eeprom(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index c810c31fbd6e..571c94835942 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -209,30 +209,31 @@ static void mt7915_led_set_config(struct led_classdev *led_cdev, u8 delay_on, u8 delay_off) { struct mt7915_dev *dev; - struct mt76_dev *mt76; + struct mt76_phy *mphy; u32 val; - mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); - dev = container_of(mt76, struct mt7915_dev, mt76); + mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); + dev = container_of(mphy->dev, struct mt7915_dev, mt76); - /* select TX blink mode, 2: only data frames */ - mt76_rmw_field(dev, MT_TMAC_TCR0(0), MT_TMAC_TCR0_TX_BLINK, 2); + /* set PWM mode */ + val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | + FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | + FIELD_PREP(MT_LED_STATUS_ON, delay_on); + mt76_wr(dev, MT_LED_STATUS_0(mphy->band_idx), val); + mt76_wr(dev, MT_LED_STATUS_1(mphy->band_idx), val); /* enable LED */ - mt76_wr(dev, MT_LED_EN(0), 1); - - /* set LED Tx blink on/off time */ - val = FIELD_PREP(MT_LED_TX_BLINK_ON_MASK, delay_on) | - FIELD_PREP(MT_LED_TX_BLINK_OFF_MASK, delay_off); - mt76_wr(dev, MT_LED_TX_BLINK(0), val); + mt76_wr(dev, MT_LED_EN(mphy->band_idx), 1); /* control LED */ - val = MT_LED_CTRL_BLINK_MODE | MT_LED_CTRL_KICK; - if (dev->mt76.led_al) + val = MT_LED_CTRL_KICK; + if (dev->mphy.leds.al) val |= MT_LED_CTRL_POLARITY; + if (mphy->band_idx) + val |= MT_LED_CTRL_BAND; - mt76_wr(dev, MT_LED_CTRL(0), val); - mt76_clear(dev, MT_LED_CTRL(0), MT_LED_CTRL_KICK); + mt76_wr(dev, MT_LED_CTRL(mphy->band_idx), val); + mt76_clear(dev, MT_LED_CTRL(mphy->band_idx), MT_LED_CTRL_KICK); } static int mt7915_led_set_blink(struct led_classdev *led_cdev, @@ -319,9 +320,10 @@ mt7915_regd_notifier(struct wiphy *wiphy, } static void -mt7915_init_wiphy(struct ieee80211_hw *hw) +mt7915_init_wiphy(struct mt7915_phy *phy) { - struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; struct mt76_dev *mdev = &phy->dev->mt76; struct wiphy *wiphy = hw->wiphy; struct mt7915_dev *dev = phy->dev; @@ -415,6 +417,12 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; + + /* init led callbacks */ + if (IS_ENABLED(CONFIG_MT76_LEDS)) { + mphy->leds.cdev.brightness_set = mt7915_led_set_brightness; + mphy->leds.cdev.blink_set = mt7915_led_set_blink; + } } static void @@ -473,6 +481,72 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set); } +static void +mt7915_init_led_mux(struct mt7915_dev *dev) +{ + if (!IS_ENABLED(CONFIG_MT76_LEDS)) + return; + + if (dev->dbdc_support) { + switch (mt76_chip(&dev->mt76)) { + case 0x7915: + mt76_rmw_field(dev, MT_LED_GPIO_MUX2, + GENMASK(11, 8), 4); + mt76_rmw_field(dev, MT_LED_GPIO_MUX3, + GENMASK(11, 8), 4); + break; + case 0x7986: + mt76_rmw_field(dev, MT_LED_GPIO_MUX0, + GENMASK(7, 4), 1); + mt76_rmw_field(dev, MT_LED_GPIO_MUX0, + GENMASK(11, 8), 1); + break; + case 0x7916: + mt76_rmw_field(dev, MT_LED_GPIO_MUX1, + GENMASK(27, 24), 3); + mt76_rmw_field(dev, MT_LED_GPIO_MUX1, + GENMASK(31, 28), 3); + break; + default: + break; + } + } else if (dev->mphy.leds.pin) { + switch (mt76_chip(&dev->mt76)) { + case 0x7915: + mt76_rmw_field(dev, MT_LED_GPIO_MUX3, + GENMASK(11, 8), 4); + break; + case 0x7986: + mt76_rmw_field(dev, MT_LED_GPIO_MUX0, + GENMASK(11, 8), 1); + break; + case 0x7916: + mt76_rmw_field(dev, MT_LED_GPIO_MUX1, + GENMASK(31, 28), 3); + break; + default: + break; + } + } else { + switch (mt76_chip(&dev->mt76)) { + case 0x7915: + mt76_rmw_field(dev, MT_LED_GPIO_MUX2, + GENMASK(11, 8), 4); + break; + case 0x7986: + mt76_rmw_field(dev, MT_LED_GPIO_MUX0, + GENMASK(7, 4), 1); + break; + case 0x7916: + mt76_rmw_field(dev, MT_LED_GPIO_MUX1, + GENMASK(27, 24), 3); + break; + default: + break; + } + } +} + void mt7915_mac_init(struct mt7915_dev *dev) { int i; @@ -497,10 +571,7 @@ void mt7915_mac_init(struct mt7915_dev *dev) for (i = 0; i < 2; i++) mt7915_mac_init_band(dev, i); - if (IS_ENABLED(CONFIG_MT76_LEDS)) { - i = dev->mt76.led_pin ? MT_LED_GPIO_MUX3 : MT_LED_GPIO_MUX2; - mt76_rmw_field(dev, i, MT_LED_GPIO_SEL_MASK, 4); - } + mt7915_init_led_mux(dev); } int mt7915_txbf_init(struct mt7915_dev *dev) @@ -569,7 +640,7 @@ mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy) mt76_eeprom_override(mphy); /* init wiphy according to mphy and phy */ - mt7915_init_wiphy(mphy->hw); + mt7915_init_wiphy(phy); ret = mt76_register_phy(mphy, true, mt76_rates, ARRAY_SIZE(mt76_rates)); @@ -1104,7 +1175,6 @@ static void mt7915_stop_hardware(struct mt7915_dev *dev) int mt7915_register_device(struct mt7915_dev *dev) { - struct ieee80211_hw *hw = mt76_hw(dev); struct mt7915_phy *phy2; int ret; @@ -1133,18 +1203,12 @@ int mt7915_register_device(struct mt7915_dev *dev) if (ret) goto free_phy2; - mt7915_init_wiphy(hw); + mt7915_init_wiphy(&dev->phy); #ifdef CONFIG_NL80211_TESTMODE dev->mt76.test_ops = &mt7915_testmode_ops; #endif - /* init led callbacks */ - if (IS_ENABLED(CONFIG_MT76_LEDS)) { - dev->mt76.led_cdev.brightness_set = mt7915_led_set_brightness; - dev->mt76.led_cdev.blink_set = mt7915_led_set_blink; - } - ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b2652de082ba..37a3c1f082d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -232,8 +232,11 @@ mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb) c = (struct mt7915_mcu_csa_notify *)skb->data; + if (c->band_idx > MT_BAND1) + return; + if ((c->band_idx && !dev->phy.mt76->band_idx) && - dev->mt76.phys[MT_BAND1]) + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, @@ -252,8 +255,11 @@ mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE) return; + if (t->ctrl.band_idx > MT_BAND1) + return; + if ((t->ctrl.band_idx && !dev->phy.mt76->band_idx) && - dev->mt76.phys[MT_BAND1]) + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; phy = (struct mt7915_phy *)mphy->priv; @@ -268,8 +274,11 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) r = (struct mt7915_mcu_rdd_report *)skb->data; + if (r->band_idx > MT_BAND1) + return; + if ((r->band_idx && !dev->phy.mt76->band_idx) && - dev->mt76.phys[MT_BAND1]) + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (r->band_idx == MT_RX_SEL2) @@ -326,7 +335,11 @@ mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb) b = (struct mt7915_mcu_bcc_notify *)skb->data; - if ((b->band_idx && !dev->phy.mt76->band_idx) && dev->mt76.phys[MT_BAND1]) + if (b->band_idx > MT_BAND1) + return; + + if ((b->band_idx && !dev->phy.mt76->band_idx) && + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, @@ -2792,8 +2805,9 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) int ret; u8 *buf; - ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS), &req, - sizeof(req), true, &skb); + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_EXT_QUERY(EFUSE_ACCESS), + &req, sizeof(req), true, &skb); if (ret) return ret; @@ -2818,8 +2832,9 @@ int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num) struct sk_buff *skb; int ret; - ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_FREE_BLOCK), &req, - sizeof(req), true, &skb); + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_EXT_QUERY(EFUSE_FREE_BLOCK), + &req, sizeof(req), true, &skb); if (ret) return ret; @@ -2974,38 +2989,42 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy) int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) { - /* strict order */ - static const u32 offs[] = { - MIB_NON_WIFI_TIME, - MIB_TX_TIME, - MIB_RX_TIME, - MIB_OBSS_AIRTIME, - MIB_TXOP_INIT_COUNT, - /* v2 */ - MIB_NON_WIFI_TIME_V2, - MIB_TX_TIME_V2, - MIB_RX_TIME_V2, - MIB_OBSS_AIRTIME_V2 - }; struct mt76_channel_state *state = phy->mt76->chan_state; struct mt76_channel_state *state_ts = &phy->state_ts; struct mt7915_dev *dev = phy->dev; struct mt7915_mcu_mib *res, req[5]; struct sk_buff *skb; - int i, ret, start = 0, ofs = 20; + static const u32 *offs; + int i, ret, len, offs_cc; u64 cc_tx; - if (!is_mt7915(&dev->mt76)) { - start = 5; - ofs = 0; + /* strict order */ + if (is_mt7915(&dev->mt76)) { + static const u32 chip_offs[] = { + MIB_NON_WIFI_TIME, + MIB_TX_TIME, + MIB_RX_TIME, + MIB_OBSS_AIRTIME, + MIB_TXOP_INIT_COUNT, + }; + len = ARRAY_SIZE(chip_offs); + offs = chip_offs; + offs_cc = 20; + } else { + static const u32 chip_offs[] = { + MIB_NON_WIFI_TIME_V2, + MIB_TX_TIME_V2, + MIB_RX_TIME_V2, + MIB_OBSS_AIRTIME_V2 + }; + len = ARRAY_SIZE(chip_offs); + offs = chip_offs; + offs_cc = 0; } - for (i = 0; i < 5; i++) { + for (i = 0; i < len; i++) { req[i].band = cpu_to_le32(phy->mt76->band_idx); - req[i].offs = cpu_to_le32(offs[i + start]); - - if (!is_mt7915(&dev->mt76) && i == 3) - break; + req[i].offs = cpu_to_le32(offs[i]); } ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO), @@ -3013,7 +3032,7 @@ int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) if (ret) return ret; - res = (struct mt7915_mcu_mib *)(skb->data + ofs); + res = (struct mt7915_mcu_mib *)(skb->data + offs_cc); #define __res_u64(s) le64_to_cpu(res[s].data) /* subtract Tx backoff time from Tx duration */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 8388e2a65853..1a2e4df8d1b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -495,7 +495,7 @@ static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr) if (dev_is_pci(dev->mt76.dev) && ((addr >= MT_CBTOP1_PHY_START && addr <= MT_CBTOP1_PHY_END) || - (addr >= MT_CBTOP2_PHY_START && addr <= MT_CBTOP2_PHY_END))) + addr >= MT_CBTOP2_PHY_START)) return mt7915_reg_map_l1(dev, addr); /* CONN_INFRA: covert to phyiscal addr and use layer 1 remap */ @@ -594,10 +594,13 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) { struct mt7915_dev *dev; - struct page *page; + u32 length; int i; dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + length = SKB_DATA_ALIGN(NET_SKB_PAD + wed->wlan.rx_size + + sizeof(struct skb_shared_info)); + for (i = 0; i < dev->mt76.rx_token_size; i++) { struct mt76_txwi_cache *t; @@ -607,18 +610,11 @@ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) dma_unmap_single(dev->mt76.dma_dev, t->dma_addr, wed->wlan.rx_size, DMA_FROM_DEVICE); - skb_free_frag(t->ptr); + __free_pages(virt_to_page(t->ptr), get_order(length)); t->ptr = NULL; mt76_put_rxwi(&dev->mt76, t); } - - if (!wed->rx_buf_ring.rx_page.va) - return; - - page = virt_to_page(wed->rx_buf_ring.rx_page.va); - __page_frag_cache_drain(page, wed->rx_buf_ring.rx_page.pagecnt_bias); - memset(&wed->rx_buf_ring.rx_page, 0, sizeof(wed->rx_buf_ring.rx_page)); } static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) @@ -635,19 +631,20 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) for (i = 0; i < size; i++) { struct mt76_txwi_cache *t = mt76_get_rxwi(&dev->mt76); dma_addr_t phy_addr; + struct page *page; int token; void *ptr; - ptr = page_frag_alloc(&wed->rx_buf_ring.rx_page, length, - GFP_KERNEL); - if (!ptr) + page = __dev_alloc_pages(GFP_KERNEL, get_order(length)); + if (!page) goto unmap; + ptr = page_address(page); phy_addr = dma_map_single(dev->mt76.dma_dev, ptr, wed->wlan.rx_size, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev->mt76.dev, phy_addr))) { - skb_free_frag(ptr); + __free_pages(page, get_order(length)); goto unmap; } @@ -656,7 +653,7 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) if (token < 0) { dma_unmap_single(dev->mt76.dma_dev, phy_addr, wed->wlan.rx_size, DMA_TO_DEVICE); - skb_free_frag(ptr); + __free_pages(page, get_order(length)); goto unmap; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index aca1b2f1e9e3..c8e478a55081 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -803,7 +803,6 @@ enum offs_rev { #define MT_CBTOP1_PHY_START 0x70000000 #define MT_CBTOP1_PHY_END __REG(CBTOP1_PHY_END) #define MT_CBTOP2_PHY_START 0xf0000000 -#define MT_CBTOP2_PHY_END 0xffffffff #define MT_INFRA_MCU_START 0x7c000000 #define MT_INFRA_MCU_END __REG(INFRA_MCU_ADDR_END) #define MT_CONN_INFRA_OFFSET(p) ((p) - MT_INFRA_BASE) @@ -1055,6 +1054,7 @@ enum offs_rev { #define MT_LED_CTRL(_n) MT_LED_PHYS(0x00 + ((_n) * 4)) #define MT_LED_CTRL_KICK BIT(7) +#define MT_LED_CTRL_BAND BIT(4) #define MT_LED_CTRL_BLINK_MODE BIT(2) #define MT_LED_CTRL_POLARITY BIT(1) @@ -1062,11 +1062,18 @@ enum offs_rev { #define MT_LED_TX_BLINK_ON_MASK GENMASK(7, 0) #define MT_LED_TX_BLINK_OFF_MASK GENMASK(15, 8) +#define MT_LED_STATUS_0(_n) MT_LED_PHYS(0x20 + ((_n) * 8)) +#define MT_LED_STATUS_1(_n) MT_LED_PHYS(0x24 + ((_n) * 8)) +#define MT_LED_STATUS_OFF GENMASK(31, 24) +#define MT_LED_STATUS_ON GENMASK(23, 16) +#define MT_LED_STATUS_DURATION GENMASK(15, 0) + #define MT_LED_EN(_n) MT_LED_PHYS(0x40 + ((_n) * 4)) +#define MT_LED_GPIO_MUX0 0x70005050 /* GPIO 1 and GPIO 2 */ +#define MT_LED_GPIO_MUX1 0x70005054 /* GPIO 14 and 15 */ #define MT_LED_GPIO_MUX2 0x70005058 /* GPIO 18 */ -#define MT_LED_GPIO_MUX3 0x7000505C /* GPIO 26 */ -#define MT_LED_GPIO_SEL_MASK GENMASK(11, 8) +#define MT_LED_GPIO_MUX3 0x7000505c /* GPIO 26 */ /* MT TOP */ #define MT_TOP_BASE 0x18060000 diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index c06c56a0270d..686c9bbd5929 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -278,6 +278,7 @@ static int mt7986_wmac_coninfra_setup(struct mt7915_dev *dev) return -EINVAL; rmem = of_reserved_mem_lookup(np); + of_node_put(np); if (!rmem) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c index 47e034a9b003..a98d0fb42d0a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c @@ -135,6 +135,22 @@ mt7921_asar_acpi_read_mtgs(struct mt7921_dev *dev, u8 **table, u8 version) return ret; } +/* MTFG : Flag Table */ +static int +mt7921_asar_acpi_read_mtfg(struct mt7921_dev *dev, u8 **table) +{ + int len, ret; + + ret = mt7921_acpi_read(dev, MT7921_ACPI_MTFG, table, &len); + if (ret) + return ret; + + if (len < MT7921_ASAR_MIN_FG) + ret = -EINVAL; + + return ret; +} + int mt7921_init_acpi_sar(struct mt7921_dev *dev) { struct mt7921_acpi_sar *asar; @@ -162,6 +178,12 @@ int mt7921_init_acpi_sar(struct mt7921_dev *dev) asar->geo = NULL; } + /* MTFG is optional */ + ret = mt7921_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg); + if (ret) { + devm_kfree(dev->mt76.dev, asar->fg); + asar->fg = NULL; + } dev->phy.acpisar = asar; return 0; @@ -280,3 +302,36 @@ int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default) return 0; } + +u8 mt7921_acpi_get_flags(struct mt7921_phy *phy) +{ + struct mt7921_asar_fg *fg; + struct { + u8 acpi_idx; + u8 chip_idx; + } map[] = { + {1, 1}, + {4, 2}, + }; + u8 flags = BIT(0); + int i, j; + + if (!phy->acpisar) + return 0; + + fg = phy->acpisar->fg; + if (!fg) + return flags; + + /* pickup necessary settings per device and + * translate the index of bitmap for chip command. + */ + for (i = 0; i < fg->nr_flag; i++) + for (j = 0; j < ARRAY_SIZE(map); j++) + if (fg->flag[i] == map[j].acpi_idx) { + flags |= BIT(map[j].chip_idx); + break; + } + + return flags; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h index 23f86bfae0c0..35268b0890ad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h @@ -8,10 +8,12 @@ #define MT7921_ASAR_MAX_DYN 8 #define MT7921_ASAR_MIN_GEO 3 #define MT7921_ASAR_MAX_GEO 8 +#define MT7921_ASAR_MIN_FG 8 #define MT7921_ACPI_MTCL "MTCL" #define MT7921_ACPI_MTDS "MTDS" #define MT7921_ACPI_MTGS "MTGS" +#define MT7921_ACPI_MTFG "MTFG" struct mt7921_asar_dyn_limit { u8 idx; @@ -77,6 +79,15 @@ struct mt7921_asar_cl { u8 cl6g[6]; } __packed; +struct mt7921_asar_fg { + u8 names[4]; + u8 version; + u8 rsvd; + u8 nr_flag; + u8 rsvd1; + u8 flag[0]; +} __packed; + struct mt7921_acpi_sar { u8 ver; union { @@ -88,6 +99,7 @@ struct mt7921_acpi_sar { struct mt7921_asar_geo_v2 *geo_v2; }; struct mt7921_asar_cl *countrylist; + struct mt7921_asar_fg *fg; }; #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 542dfd425129..d4b681d7e1d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -175,7 +175,7 @@ u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm) if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev, "Invalid firmware\n"); - return -EINVAL; + goto out; } data = fw->data; @@ -206,6 +206,7 @@ u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm) data += le16_to_cpu(rel_info->len) + rel_info->pad_len; } +out: release_firmware(fw); return features ? features->data : 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index fb9c0f66cb27..8930b5a4467c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1184,13 +1184,15 @@ int __mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2, __le16 len; u8 idx; u8 env; - u8 pad1[2]; + u8 acpi_conf; + u8 pad1; u8 alpha2[2]; u8 type[2]; u8 rsvd[64]; } __packed req = { .idx = idx, .env = env_cap, + .acpi_conf = mt7921_acpi_get_flags(&dev->phy), }; int ret, valid_cnt = 0; u8 i, *pos; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 15d6b7fe1c6c..efff4d43d796 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -554,6 +554,7 @@ int mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, #ifdef CONFIG_ACPI int mt7921_init_acpi_sar(struct mt7921_dev *dev); int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default); +u8 mt7921_acpi_get_flags(struct mt7921_phy *phy); #else static inline int mt7921_init_acpi_sar(struct mt7921_dev *dev) @@ -566,6 +567,12 @@ mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default) { return 0; } + +static inline u8 +mt7921_acpi_get_flags(struct mt7921_phy *phy) +{ + return 0; +} #endif int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c index 2e4a8909b9e8..3d4fbbbcc206 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c @@ -457,7 +457,7 @@ mt7996_hw_queue_read(struct seq_file *s, u32 size, if (val & BIT(map[i].index)) continue; - ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24); + ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24); mt76_wr(dev, MT_FL_Q0_CTRL, ctrl); head = mt76_get_field(dev, MT_FL_Q2_CTRL, @@ -653,8 +653,9 @@ static int mt7996_rf_regval_set(void *data, u64 val) { struct mt7996_dev *dev = data; + u32 val32 = val; - return mt7996_mcu_rf_regval(dev, dev->mt76.debugfs_reg, (u32 *)&val, true); + return mt7996_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true); } DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7996_rf_regval_get, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index b9f62bedbc48..5d8e0353627e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -65,17 +65,23 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev) } else { u8 free_block_num; u32 block_num, i; + u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; - /* TODO: check free block event */ - mt7996_mcu_get_eeprom_free_block(dev, &free_block_num); - /* efuse info not enough */ + ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num); + if (ret < 0) + return ret; + + /* efuse info isn't enough */ if (free_block_num >= 59) return -EINVAL; /* read eeprom data from efuse */ - block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, MT7996_EEPROM_BLOCK_SIZE); - for (i = 0; i < block_num; i++) - mt7996_mcu_get_eeprom(dev, i * MT7996_EEPROM_BLOCK_SIZE); + block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); + for (i = 0; i < block_num; i++) { + ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size); + if (ret < 0) + return ret; + } } return mt7996_check_eeprom(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 46b290526092..64e8dfd06e9f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -46,11 +46,11 @@ static void mt7996_led_set_config(struct led_classdev *led_cdev, u8 delay_on, u8 delay_off) { struct mt7996_dev *dev; - struct mt76_dev *mt76; + struct mt76_phy *mphy; u32 val; - mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); - dev = container_of(mt76, struct mt7996_dev, mt76); + mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); + dev = container_of(mphy->dev, struct mt7996_dev, mt76); /* select TX blink mode, 2: only data frames */ mt76_rmw_field(dev, MT_TMAC_TCR0(0), MT_TMAC_TCR0_TX_BLINK, 2); @@ -65,7 +65,7 @@ static void mt7996_led_set_config(struct led_classdev *led_cdev, /* control LED */ val = MT_LED_CTRL_BLINK_MODE | MT_LED_CTRL_KICK; - if (dev->mt76.led_al) + if (mphy->leds.al) val |= MT_LED_CTRL_POLARITY; mt76_wr(dev, MT_LED_CTRL(0), val); @@ -261,7 +261,7 @@ static void mt7996_mac_init(struct mt7996_dev *dev) MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (IS_ENABLED(CONFIG_MT76_LEDS)) { - i = dev->mt76.led_pin ? MT_LED_GPIO_MUX3 : MT_LED_GPIO_MUX2; + i = dev->mphy.leds.pin ? MT_LED_GPIO_MUX3 : MT_LED_GPIO_MUX2; mt76_rmw_field(dev, i, MT_LED_GPIO_SEL_MASK, 4); } @@ -787,8 +787,8 @@ int mt7996_register_device(struct mt7996_dev *dev) /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { - dev->mt76.led_cdev.brightness_set = mt7996_led_set_brightness; - dev->mt76.led_cdev.blink_set = mt7996_led_set_blink; + dev->mphy.leds.cdev.brightness_set = mt7996_led_set_brightness; + dev->mphy.leds.cdev.blink_set = mt7996_led_set_blink; } ret = mt76_register_device(&dev->mt76, true, mt76_rates, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 04e1d10bbd21..a88fc7680b1a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -335,6 +335,9 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) r = (struct mt7996_mcu_rdd_report *)skb->data; + if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys)) + return; + mphy = dev->mt76.phys[r->band_idx]; if (!mphy) return; @@ -412,6 +415,9 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) struct header *hdr = (struct header *)data; struct tlv *tlv = (struct tlv *)(data + 4); + if (hdr->band >= ARRAY_SIZE(dev->mt76.phys)) + return; + if (hdr->band && dev->mt76.phys[hdr->band]) mphy = dev->mt76.phys[hdr->band]; @@ -903,8 +909,8 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) he = (struct sta_rec_he_v2 *)tlv; for (i = 0; i < 11; i++) { if (i < 6) - he->he_mac_cap[i] = cpu_to_le16(elem->mac_cap_info[i]); - he->he_phy_cap[i] = cpu_to_le16(elem->phy_cap_info[i]); + he->he_mac_cap[i] = elem->mac_cap_info[i]; + he->he_phy_cap[i] = elem->phy_cap_info[i]; } mcs_map = sta->deflink.he_cap.he_mcs_nss_supp; @@ -2921,8 +2927,9 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset) bool valid; int ret; - ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), &req, - sizeof(req), true, &skb); + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), + &req, sizeof(req), true, &skb); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 521769eb6b0e..60781d046216 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -149,7 +149,7 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) if (dev_is_pci(dev->mt76.dev) && ((addr >= MT_CBTOP1_PHY_START && addr <= MT_CBTOP1_PHY_END) || - (addr >= MT_CBTOP2_PHY_START && addr <= MT_CBTOP2_PHY_END))) + addr >= MT_CBTOP2_PHY_START)) return mt7996_reg_map_l1(dev, addr); /* CONN_INFRA: covert to phyiscal addr and use layer 1 remap */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 794f61b93a46..42980b97b4d4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -463,7 +463,6 @@ enum base_rev { #define MT_CBTOP1_PHY_START 0x70000000 #define MT_CBTOP1_PHY_END 0x77ffffff #define MT_CBTOP2_PHY_START 0xf0000000 -#define MT_CBTOP2_PHY_END 0xffffffff #define MT_INFRA_MCU_START 0x7c000000 #define MT_INFRA_MCU_END 0x7c3fffff diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c index bfc4de50a4d2..ddd8c0cc744d 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -254,6 +254,10 @@ static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q) if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) { __skb_put_zero(e->skb, 4); + err = __skb_grow(e->skb, roundup(e->skb->len, + sdio->func->cur_blksize)); + if (err) + return err; err = __mt76s_xmit_queue(dev, e->skb->data, e->skb->len); if (err) diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index 457147394edc..773a1cc2f852 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -123,7 +123,8 @@ static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) if (data_len < min_seg_len || WARN_ON_ONCE(!dma_len) || WARN_ON_ONCE(dma_len + MT_DMA_HDRS > data_len) || - WARN_ON_ONCE(dma_len & 0x3)) + WARN_ON_ONCE(dma_len & 0x3) || + WARN_ON_ONCE(dma_len < min_seg_len)) return 0; return MT_DMA_HDRS + dma_len; diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 9b319a455b96..e9f59de31b0b 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -730,6 +730,7 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) if (skb->dev != ndev) { netdev_err(ndev, "Packet not destined to this device\n"); + dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -980,7 +981,7 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, ndev->name); if (!wl->hif_workqueue) { ret = -ENOMEM; - goto error; + goto unregister_netdev; } ndev->needs_free_netdev = true; @@ -995,6 +996,11 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, return vif; +unregister_netdev: + if (rtnl_locked) + cfg80211_unregister_netdevice(ndev); + else + unregister_netdev(ndev); error: free_netdev(ndev); return ERR_PTR(ret); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 12b700c7b9c3..1226a883cd67 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -8924,8 +8924,6 @@ static void rt2800_rxiq_calibration(struct rt2x00_dev *rt2x00dev) if (i < 2 && (bbptemp & 0x800000)) result = (bbptemp & 0xffffff) - 0x1000000; - else if (i == 4) - result = bbptemp; else result = bbptemp; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig index 631d078278be..091d3ad98093 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig +++ b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig @@ -10,7 +10,7 @@ config RTL8XXXU parts written to utilize the Linux mac80211 stack. The driver is known to work with a number of RTL8723AU, RL8188CU, RTL8188RU, RTL8191CU, RTL8192CU, RTL8723BU, RTL8192EU, - and RTL8188FU devices. + RTL8188FU, and RTL8188EU devices. This driver is under development and has a limited feature set. In particular it does not yet support 40MHz channels diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Makefile b/drivers/net/wireless/realtek/rtl8xxxu/Makefile index c4ad5325f5e7..0cb58fb30228 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/Makefile +++ b/drivers/net/wireless/realtek/rtl8xxxu/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o rtl8xxxu-y := rtl8xxxu_core.o rtl8xxxu_8192e.o rtl8xxxu_8723b.o \ - rtl8xxxu_8723a.o rtl8xxxu_8192c.o rtl8xxxu_8188f.o + rtl8xxxu_8723a.o rtl8xxxu_8192c.o rtl8xxxu_8188f.o \ + rtl8xxxu_8188e.o diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index d26df4095da0..90268479d3ad 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -36,6 +36,7 @@ #define TX_TOTAL_PAGE_NUM 0xf8 #define TX_TOTAL_PAGE_NUM_8188F 0xf7 +#define TX_TOTAL_PAGE_NUM_8188E 0xa9 #define TX_TOTAL_PAGE_NUM_8192E 0xf3 #define TX_TOTAL_PAGE_NUM_8723B 0xf7 /* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */ @@ -49,6 +50,11 @@ #define TX_PAGE_NUM_LO_PQ_8188F 0x02 #define TX_PAGE_NUM_NORM_PQ_8188F 0x02 +#define TX_PAGE_NUM_PUBQ_8188E 0x47 +#define TX_PAGE_NUM_HI_PQ_8188E 0x29 +#define TX_PAGE_NUM_LO_PQ_8188E 0x1c +#define TX_PAGE_NUM_NORM_PQ_8188E 0x1c + #define TX_PAGE_NUM_PUBQ_8192E 0xe7 #define TX_PAGE_NUM_HI_PQ_8192E 0x08 #define TX_PAGE_NUM_LO_PQ_8192E 0x0c @@ -153,7 +159,8 @@ struct rtl8xxxu_rxdesc16 { u32 htc:1; u32 eosp:1; u32 bssidfit:2; - u32 reserved1:16; + u32 rpt_sel:2; /* 8188e */ + u32 reserved1:14; u32 unicastwake:1; u32 magicwake:1; @@ -211,7 +218,8 @@ struct rtl8xxxu_rxdesc16 { u32 magicwake:1; u32 unicastwake:1; - u32 reserved1:16; + u32 reserved1:14; + u32 rpt_sel:2; /* 8188e */ u32 bssidfit:2; u32 eosp:1; u32 htc:1; @@ -502,6 +510,8 @@ struct rtl8xxxu_txdesc40 { #define TXDESC_AMPDU_DENSITY_SHIFT 20 #define TXDESC40_BT_INT BIT(23) #define TXDESC40_GID_SHIFT 24 +#define TXDESC_ANTENNA_SELECT_A BIT(24) +#define TXDESC_ANTENNA_SELECT_B BIT(25) /* Word 3 */ #define TXDESC40_USE_DRIVER_RATE BIT(8) @@ -521,6 +531,7 @@ struct rtl8xxxu_txdesc40 { #define TXDESC32_CTS_SELF_ENABLE BIT(11) #define TXDESC32_RTS_CTS_ENABLE BIT(12) #define TXDESC32_HW_RTS_ENABLE BIT(13) +#define TXDESC32_PT_STAGE_MASK GENMASK(17, 15) #define TXDESC_PRIME_CH_OFF_LOWER BIT(20) #define TXDESC_PRIME_CH_OFF_UPPER BIT(21) #define TXDESC32_SHORT_PREAMBLE BIT(24) @@ -546,6 +557,10 @@ struct rtl8xxxu_txdesc40 { /* Word 6 */ #define TXDESC_MAX_AGG_SHIFT 11 +#define TXDESC_USB_TX_AGG_SHIT 24 + +/* Word 7 */ +#define TXDESC_ANTENNA_SELECT_C BIT(29) /* Word 8 */ #define TXDESC40_HW_SEQ_ENABLE BIT(15) @@ -562,6 +577,9 @@ struct phy_rx_agc_info { #endif }; +#define CCK_AGC_RPT_LNA_IDX_MASK GENMASK(7, 5) +#define CCK_AGC_RPT_VGA_IDX_MASK GENMASK(4, 0) + struct rtl8723au_phy_stats { struct phy_rx_agc_info path_agc[RTL8723A_MAX_RF_PATHS]; u8 ch_corr[RTL8723A_MAX_RF_PATHS]; @@ -909,6 +927,42 @@ struct rtl8188fu_efuse { u8 res11[0xc3]; }; +struct rtl8188eu_efuse { + __le16 rtl_id; + u8 res0[0x0e]; + struct rtl8192eu_efuse_tx_power tx_power_index_A; /* 0x10 */ + u8 res1[0x7e]; /* 0x3a */ + u8 channel_plan; /* 0xb8 */ + u8 xtal_k; + u8 thermal_meter; + u8 iqk_lck; + u8 res2[5]; + u8 rf_board_option; + u8 rf_feature_option; + u8 rf_bt_setting; + u8 eeprom_version; + u8 eeprom_customer_id; + u8 res3[3]; + u8 rf_antenna_option; /* 0xc9 */ + u8 res4[6]; + u8 vid; /* 0xd0 */ + u8 res5[1]; + u8 pid; /* 0xd2 */ + u8 res6[1]; + u8 usb_optional_function; + u8 res7[2]; + u8 mac_addr[ETH_ALEN]; /* 0xd7 */ + u8 res8[2]; + u8 vendor_name[7]; + u8 res9[2]; + u8 device_name[0x0b]; /* 0xe8 */ + u8 res10[2]; + u8 serial[0x0b]; /* 0xf5 */ + u8 res11[0x30]; + u8 unknown[0x0d]; /* 0x130 */ + u8 res12[0xc3]; +} __packed; + struct rtl8xxxu_reg8val { u16 reg; u8 val; @@ -1114,6 +1168,26 @@ struct h2c_cmd { u8 cmd; u8 data; } __packed bt_grant; + struct { + u8 cmd; + u8 macid; + u8 unknown0; + u8 rssi; + /* + * [0] - is_rx + * [1] - stbc_en + * [2] - noisy_decision + * [6] - bf_en + */ + u8 data; + /* + * [0:6] - ra_th_offset + * [7] - ra_offset_direction + */ + u8 ra_th_offset; + u8 unknown1; + u8 unknown2; + } __packed rssi_report; }; }; @@ -1323,6 +1397,39 @@ struct rtl8xxxu_ra_report { u8 desc_rate; }; +struct rtl8xxxu_ra_info { + u8 rate_id; + u32 rate_mask; + u32 ra_use_rate; + u8 rate_sgi; + u8 rssi_sta_ra; /* Percentage */ + u8 pre_rssi_sta_ra; + u8 sgi_enable; + u8 decision_rate; + u8 pre_rate; + u8 highest_rate; + u8 lowest_rate; + u32 nsc_up; + u32 nsc_down; + u32 total; + u16 retry[5]; + u16 drop; + u16 rpt_time; + u16 pre_min_rpt_time; + u8 dynamic_tx_rpt_timing_counter; + u8 ra_waiting_counter; + u8 ra_pending_counter; + u8 ra_drop_after_down; + u8 pt_try_state; /* 0 trying state, 1 for decision state */ + u8 pt_stage; /* 0~6 */ + u8 pt_stop_count; /* Stop PT counter */ + u8 pt_pre_rate; /* if rate change do PT */ + u8 pt_pre_rssi; /* if RSSI change 5% do PT */ + u8 pt_mode_ss; /* decide which rate should do PT */ + u8 ra_stage; /* StageRA, decide how many times RA will be done between PT */ + u8 pt_smooth_factor; +}; + #define CFO_TH_XTAL_HIGH 20 /* kHz */ #define CFO_TH_XTAL_LOW 10 /* kHz */ #define CFO_TH_ATC 80 /* kHz */ @@ -1432,6 +1539,7 @@ struct rtl8xxxu_priv { struct rtl8192cu_efuse efuse8192; struct rtl8192eu_efuse efuse8192eu; struct rtl8188fu_efuse efuse8188fu; + struct rtl8188eu_efuse efuse8188eu; } efuse_wifi; u32 adda_backup[RTL8XXXU_ADDA_REGS]; u32 mac_backup[RTL8XXXU_MAC_REGS]; @@ -1455,6 +1563,7 @@ struct rtl8xxxu_priv { struct rtl8xxxu_btcoex bt_coex; struct rtl8xxxu_ra_report ra_report; struct rtl8xxxu_cfo_tracking cfo_tracking; + struct rtl8xxxu_ra_info ra_info; }; struct rtl8xxxu_rx_urb { @@ -1496,6 +1605,7 @@ struct rtl8xxxu_fileops { u32 ramask, u8 rateid, int sgi, int txbw_40mhz); void (*report_connect) (struct rtl8xxxu_priv *priv, u8 macid, bool connect); + void (*report_rssi) (struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, @@ -1523,6 +1633,7 @@ struct rtl8xxxu_fileops { u8 page_num_hi; u8 page_num_lo; u8 page_num_norm; + u8 last_llt_entry; }; extern int rtl8xxxu_debug; @@ -1560,7 +1671,7 @@ int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv, enum rtl8xxxu_rfpath path); int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv, const struct rtl8xxxu_reg32val *array); -int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name); +int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, const char *fw_name); void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv); void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv); void rtl8xxxu_identify_vendor_1bit(struct rtl8xxxu_priv *priv, u32 vendor); @@ -1582,6 +1693,8 @@ void rtl8xxxu_gen1_phy_iq_calibrate(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_init_phy_bb(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40); +void rtl8188f_set_tx_power(struct rtl8xxxu_priv *priv, + int channel, bool ht40); void rtl8xxxu_gen1_config_channel(struct ieee80211_hw *hw); void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw); void rtl8xxxu_gen1_usb_quirks(struct rtl8xxxu_priv *priv); @@ -1594,6 +1707,8 @@ void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, u8 macid, bool connect); void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, u8 macid, bool connect); +void rtl8xxxu_gen1_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); +void rtl8xxxu_gen2_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_enable_rf(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_disable_rf(struct rtl8xxxu_priv *priv); @@ -1602,6 +1717,8 @@ void rtl8xxxu_init_burst(struct rtl8xxxu_priv *priv); int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb); int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb); int rtl8xxxu_gen2_channel_to_group(int channel); +bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv, + int result[][8], int c1, int c2); bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv, int result[][8], int c1, int c2); void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, @@ -1614,13 +1731,24 @@ void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, bool short_preamble, bool ampdu_enable, u32 rts_rate); +void rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + struct ieee80211_tx_info *tx_info, + struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, + bool short_preamble, bool ampdu_enable, + u32 rts_rate); void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5); void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv); void rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap); +void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap); s8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt); +void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt, + u8 rate, u8 sgi, u8 bw); +void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra); +void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *skb); extern struct rtl8xxxu_fileops rtl8188fu_fops; +extern struct rtl8xxxu_fileops rtl8188eu_fops; extern struct rtl8xxxu_fileops rtl8192cu_fops; extern struct rtl8xxxu_fileops rtl8192eu_fops; extern struct rtl8xxxu_fileops rtl8723au_fops; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c new file mode 100644 index 000000000000..08f3b93ad8d0 --- /dev/null +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c @@ -0,0 +1,1874 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RTL8XXXU mac80211 USB driver - 8188e specific subdriver + * + * Copyright (c) 2014 - 2016 Jes Sorensen <Jes.Sorensen@gmail.com> + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This driver was written as a replacement for the vendor provided + * rtl8723au driver. As the Realtek 8xxx chips are very similar in + * their programming interface, I have started adding support for + * additional 8xxx chips like the 8192cu, 8188cus, etc. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/usb.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/wireless.h> +#include <linux/firmware.h> +#include <linux/moduleparam.h> +#include <net/mac80211.h> +#include "rtl8xxxu.h" +#include "rtl8xxxu_regs.h" + +static const struct rtl8xxxu_reg8val rtl8188e_mac_init_table[] = { + {0x026, 0x41}, {0x027, 0x35}, {0x040, 0x00}, {0x421, 0x0f}, + {0x428, 0x0a}, {0x429, 0x10}, {0x430, 0x00}, {0x431, 0x01}, + {0x432, 0x02}, {0x433, 0x04}, {0x434, 0x05}, {0x435, 0x06}, + {0x436, 0x07}, {0x437, 0x08}, {0x438, 0x00}, {0x439, 0x00}, + {0x43a, 0x01}, {0x43b, 0x02}, {0x43c, 0x04}, {0x43d, 0x05}, + {0x43e, 0x06}, {0x43f, 0x07}, {0x440, 0x5d}, {0x441, 0x01}, + {0x442, 0x00}, {0x444, 0x15}, {0x445, 0xf0}, {0x446, 0x0f}, + {0x447, 0x00}, {0x458, 0x41}, {0x459, 0xa8}, {0x45a, 0x72}, + {0x45b, 0xb9}, {0x460, 0x66}, {0x461, 0x66}, {0x480, 0x08}, + {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff}, {0x4cd, 0xff}, + {0x4ce, 0x01}, {0x4d3, 0x01}, {0x500, 0x26}, {0x501, 0xa2}, + {0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3}, + {0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4}, + {0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4}, + {0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a}, + {0x516, 0x0a}, {0x525, 0x4f}, {0x550, 0x10}, {0x551, 0x10}, + {0x559, 0x02}, {0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, + {0x609, 0x2a}, {0x620, 0xff}, {0x621, 0xff}, {0x622, 0xff}, + {0x623, 0xff}, {0x624, 0xff}, {0x625, 0xff}, {0x626, 0xff}, + {0x627, 0xff}, {0x63c, 0x08}, {0x63d, 0x08}, {0x63e, 0x0c}, + {0x63f, 0x0c}, {0x640, 0x40}, {0x652, 0x20}, {0x66e, 0x05}, + {0x700, 0x21}, {0x701, 0x43}, {0x702, 0x65}, {0x703, 0x87}, + {0x708, 0x21}, {0x709, 0x43}, {0x70a, 0x65}, {0x70b, 0x87}, + {0xffff, 0xff}, +}; + +static const struct rtl8xxxu_reg32val rtl8188eu_phy_init_table[] = { + {0x800, 0x80040000}, {0x804, 0x00000003}, + {0x808, 0x0000fc00}, {0x80c, 0x0000000a}, + {0x810, 0x10001331}, {0x814, 0x020c3d10}, + {0x818, 0x02200385}, {0x81c, 0x00000000}, + {0x820, 0x01000100}, {0x824, 0x00390204}, + {0x828, 0x00000000}, {0x82c, 0x00000000}, + {0x830, 0x00000000}, {0x834, 0x00000000}, + {0x838, 0x00000000}, {0x83c, 0x00000000}, + {0x840, 0x00010000}, {0x844, 0x00000000}, + {0x848, 0x00000000}, {0x84c, 0x00000000}, + {0x850, 0x00000000}, {0x854, 0x00000000}, + {0x858, 0x569a11a9}, {0x85c, 0x01000014}, + {0x860, 0x66f60110}, {0x864, 0x061f0649}, + {0x868, 0x00000000}, {0x86c, 0x27272700}, + {0x870, 0x07000760}, {0x874, 0x25004000}, + {0x878, 0x00000808}, {0x87c, 0x00000000}, + {0x880, 0xb0000c1c}, {0x884, 0x00000001}, + {0x888, 0x00000000}, {0x88c, 0xccc000c0}, + {0x890, 0x00000800}, {0x894, 0xfffffffe}, + {0x898, 0x40302010}, {0x89c, 0x00706050}, + {0x900, 0x00000000}, {0x904, 0x00000023}, + {0x908, 0x00000000}, {0x90c, 0x81121111}, + {0x910, 0x00000002}, {0x914, 0x00000201}, + {0xa00, 0x00d047c8}, {0xa04, 0x80ff800c}, + {0xa08, 0x8c838300}, {0xa0c, 0x2e7f120f}, + {0xa10, 0x9500bb7e}, {0xa14, 0x1114d028}, + {0xa18, 0x00881117}, {0xa1c, 0x89140f00}, + {0xa20, 0x1a1b0000}, {0xa24, 0x090e1317}, + {0xa28, 0x00000204}, {0xa2c, 0x00d30000}, + {0xa70, 0x101fbf00}, {0xa74, 0x00000007}, + {0xa78, 0x00000900}, {0xa7c, 0x225b0606}, + {0xa80, 0x218075b1}, {0xb2c, 0x80000000}, + {0xc00, 0x48071d40}, {0xc04, 0x03a05611}, + {0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c}, + {0xc10, 0x08800000}, {0xc14, 0x40000100}, + {0xc18, 0x08800000}, {0xc1c, 0x40000100}, + {0xc20, 0x00000000}, {0xc24, 0x00000000}, + {0xc28, 0x00000000}, {0xc2c, 0x00000000}, + {0xc30, 0x69e9ac47}, {0xc34, 0x469652af}, + {0xc38, 0x49795994}, {0xc3c, 0x0a97971c}, + {0xc40, 0x1f7c403f}, {0xc44, 0x000100b7}, + {0xc48, 0xec020107}, {0xc4c, 0x007f037f}, + {0xc50, 0x69553420}, {0xc54, 0x43bc0094}, + {0xc58, 0x00013169}, {0xc5c, 0x00250492}, + {0xc60, 0x00000000}, {0xc64, 0x7112848b}, + {0xc68, 0x47c00bff}, {0xc6c, 0x00000036}, + {0xc70, 0x2c7f000d}, {0xc74, 0x020610db}, + {0xc78, 0x0000001f}, {0xc7c, 0x00b91612}, + {0xc80, 0x390000e4}, {0xc84, 0x21f60000}, + {0xc88, 0x40000100}, {0xc8c, 0x20200000}, + {0xc90, 0x00091521}, {0xc94, 0x00000000}, + {0xc98, 0x00121820}, {0xc9c, 0x00007f7f}, + {0xca0, 0x00000000}, {0xca4, 0x000300a0}, + {0xca8, 0x00000000}, {0xcac, 0x00000000}, + {0xcb0, 0x00000000}, {0xcb4, 0x00000000}, + {0xcb8, 0x00000000}, {0xcbc, 0x28000000}, + {0xcc0, 0x00000000}, {0xcc4, 0x00000000}, + {0xcc8, 0x00000000}, {0xccc, 0x00000000}, + {0xcd0, 0x00000000}, {0xcd4, 0x00000000}, + {0xcd8, 0x64b22427}, {0xcdc, 0x00766932}, + {0xce0, 0x00222222}, {0xce4, 0x00000000}, + {0xce8, 0x37644302}, {0xcec, 0x2f97d40c}, + {0xd00, 0x00000740}, {0xd04, 0x00020401}, + {0xd08, 0x0000907f}, {0xd0c, 0x20010201}, + {0xd10, 0xa0633333}, {0xd14, 0x3333bc43}, + {0xd18, 0x7a8f5b6f}, {0xd2c, 0xcc979975}, + {0xd30, 0x00000000}, {0xd34, 0x80608000}, + {0xd38, 0x00000000}, {0xd3c, 0x00127353}, + {0xd40, 0x00000000}, {0xd44, 0x00000000}, + {0xd48, 0x00000000}, {0xd4c, 0x00000000}, + {0xd50, 0x6437140a}, {0xd54, 0x00000000}, + {0xd58, 0x00000282}, {0xd5c, 0x30032064}, + {0xd60, 0x4653de68}, {0xd64, 0x04518a3c}, + {0xd68, 0x00002101}, {0xd6c, 0x2a201c16}, + {0xd70, 0x1812362e}, {0xd74, 0x322c2220}, + {0xd78, 0x000e3c24}, {0xe00, 0x2d2d2d2d}, + {0xe04, 0x2d2d2d2d}, {0xe08, 0x0390272d}, + {0xe10, 0x2d2d2d2d}, {0xe14, 0x2d2d2d2d}, + {0xe18, 0x2d2d2d2d}, {0xe1c, 0x2d2d2d2d}, + {0xe28, 0x00000000}, {0xe30, 0x1000dc1f}, + {0xe34, 0x10008c1f}, {0xe38, 0x02140102}, + {0xe3c, 0x681604c2}, {0xe40, 0x01007c00}, + {0xe44, 0x01004800}, {0xe48, 0xfb000000}, + {0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f}, + {0xe54, 0x10008c1f}, {0xe58, 0x02140102}, + {0xe5c, 0x28160d05}, {0xe60, 0x00000048}, + {0xe68, 0x001b25a4}, {0xe6c, 0x00c00014}, + {0xe70, 0x00c00014}, {0xe74, 0x01000014}, + {0xe78, 0x01000014}, {0xe7c, 0x01000014}, + {0xe80, 0x01000014}, {0xe84, 0x00c00014}, + {0xe88, 0x01000014}, {0xe8c, 0x00c00014}, + {0xed0, 0x00c00014}, {0xed4, 0x00c00014}, + {0xed8, 0x00c00014}, {0xedc, 0x00000014}, + {0xee0, 0x00000014}, {0xee8, 0x21555448}, + {0xeec, 0x01c00014}, {0xf14, 0x00000003}, + {0xf4c, 0x00000000}, {0xf00, 0x00000300}, + {0xffff, 0xffffffff}, +}; + +static const struct rtl8xxxu_reg32val rtl8188e_agc_table[] = { + {0xc78, 0xfb000001}, {0xc78, 0xfb010001}, + {0xc78, 0xfb020001}, {0xc78, 0xfb030001}, + {0xc78, 0xfb040001}, {0xc78, 0xfb050001}, + {0xc78, 0xfa060001}, {0xc78, 0xf9070001}, + {0xc78, 0xf8080001}, {0xc78, 0xf7090001}, + {0xc78, 0xf60a0001}, {0xc78, 0xf50b0001}, + {0xc78, 0xf40c0001}, {0xc78, 0xf30d0001}, + {0xc78, 0xf20e0001}, {0xc78, 0xf10f0001}, + {0xc78, 0xf0100001}, {0xc78, 0xef110001}, + {0xc78, 0xee120001}, {0xc78, 0xed130001}, + {0xc78, 0xec140001}, {0xc78, 0xeb150001}, + {0xc78, 0xea160001}, {0xc78, 0xe9170001}, + {0xc78, 0xe8180001}, {0xc78, 0xe7190001}, + {0xc78, 0xe61a0001}, {0xc78, 0xe51b0001}, + {0xc78, 0xe41c0001}, {0xc78, 0xe31d0001}, + {0xc78, 0xe21e0001}, {0xc78, 0xe11f0001}, + {0xc78, 0x8a200001}, {0xc78, 0x89210001}, + {0xc78, 0x88220001}, {0xc78, 0x87230001}, + {0xc78, 0x86240001}, {0xc78, 0x85250001}, + {0xc78, 0x84260001}, {0xc78, 0x83270001}, + {0xc78, 0x82280001}, {0xc78, 0x6b290001}, + {0xc78, 0x6a2a0001}, {0xc78, 0x692b0001}, + {0xc78, 0x682c0001}, {0xc78, 0x672d0001}, + {0xc78, 0x662e0001}, {0xc78, 0x652f0001}, + {0xc78, 0x64300001}, {0xc78, 0x63310001}, + {0xc78, 0x62320001}, {0xc78, 0x61330001}, + {0xc78, 0x46340001}, {0xc78, 0x45350001}, + {0xc78, 0x44360001}, {0xc78, 0x43370001}, + {0xc78, 0x42380001}, {0xc78, 0x41390001}, + {0xc78, 0x403a0001}, {0xc78, 0x403b0001}, + {0xc78, 0x403c0001}, {0xc78, 0x403d0001}, + {0xc78, 0x403e0001}, {0xc78, 0x403f0001}, + {0xc78, 0xfb400001}, {0xc78, 0xfb410001}, + {0xc78, 0xfb420001}, {0xc78, 0xfb430001}, + {0xc78, 0xfb440001}, {0xc78, 0xfb450001}, + {0xc78, 0xfb460001}, {0xc78, 0xfb470001}, + {0xc78, 0xfb480001}, {0xc78, 0xfa490001}, + {0xc78, 0xf94a0001}, {0xc78, 0xf84b0001}, + {0xc78, 0xf74c0001}, {0xc78, 0xf64d0001}, + {0xc78, 0xf54e0001}, {0xc78, 0xf44f0001}, + {0xc78, 0xf3500001}, {0xc78, 0xf2510001}, + {0xc78, 0xf1520001}, {0xc78, 0xf0530001}, + {0xc78, 0xef540001}, {0xc78, 0xee550001}, + {0xc78, 0xed560001}, {0xc78, 0xec570001}, + {0xc78, 0xeb580001}, {0xc78, 0xea590001}, + {0xc78, 0xe95a0001}, {0xc78, 0xe85b0001}, + {0xc78, 0xe75c0001}, {0xc78, 0xe65d0001}, + {0xc78, 0xe55e0001}, {0xc78, 0xe45f0001}, + {0xc78, 0xe3600001}, {0xc78, 0xe2610001}, + {0xc78, 0xc3620001}, {0xc78, 0xc2630001}, + {0xc78, 0xc1640001}, {0xc78, 0x8b650001}, + {0xc78, 0x8a660001}, {0xc78, 0x89670001}, + {0xc78, 0x88680001}, {0xc78, 0x87690001}, + {0xc78, 0x866a0001}, {0xc78, 0x856b0001}, + {0xc78, 0x846c0001}, {0xc78, 0x676d0001}, + {0xc78, 0x666e0001}, {0xc78, 0x656f0001}, + {0xc78, 0x64700001}, {0xc78, 0x63710001}, + {0xc78, 0x62720001}, {0xc78, 0x61730001}, + {0xc78, 0x60740001}, {0xc78, 0x46750001}, + {0xc78, 0x45760001}, {0xc78, 0x44770001}, + {0xc78, 0x43780001}, {0xc78, 0x42790001}, + {0xc78, 0x417a0001}, {0xc78, 0x407b0001}, + {0xc78, 0x407c0001}, {0xc78, 0x407d0001}, + {0xc78, 0x407e0001}, {0xc78, 0x407f0001}, + {0xc50, 0x69553422}, {0xc50, 0x69553420}, + {0xffff, 0xffffffff} +}; + +static const struct rtl8xxxu_rfregval rtl8188eu_radioa_init_table[] = { + {0x00, 0x00030000}, {0x08, 0x00084000}, + {0x18, 0x00000407}, {0x19, 0x00000012}, + {0x1e, 0x00080009}, {0x1f, 0x00000880}, + {0x2f, 0x0001a060}, {0x3f, 0x00000000}, + {0x42, 0x000060c0}, {0x57, 0x000d0000}, + {0x58, 0x000be180}, {0x67, 0x00001552}, + {0x83, 0x00000000}, {0xb0, 0x000ff8fc}, + {0xb1, 0x00054400}, {0xb2, 0x000ccc19}, + {0xb4, 0x00043003}, {0xb6, 0x0004953e}, + {0xb7, 0x0001c718}, {0xb8, 0x000060ff}, + {0xb9, 0x00080001}, {0xba, 0x00040000}, + {0xbb, 0x00000400}, {0xbf, 0x000c0000}, + {0xc2, 0x00002400}, {0xc3, 0x00000009}, + {0xc4, 0x00040c91}, {0xc5, 0x00099999}, + {0xc6, 0x000000a3}, {0xc7, 0x00088820}, + {0xc8, 0x00076c06}, {0xc9, 0x00000000}, + {0xca, 0x00080000}, {0xdf, 0x00000180}, + {0xef, 0x000001a0}, {0x51, 0x0006b27d}, + {0x52, 0x0007e49d}, /* Set to 0x0007e4dd for SDIO */ + {0x53, 0x00000073}, {0x56, 0x00051ff3}, + {0x35, 0x00000086}, {0x35, 0x00000186}, + {0x35, 0x00000286}, {0x36, 0x00001c25}, + {0x36, 0x00009c25}, {0x36, 0x00011c25}, + {0x36, 0x00019c25}, {0xb6, 0x00048538}, + {0x18, 0x00000c07}, {0x5a, 0x0004bd00}, + {0x19, 0x000739d0}, {0x34, 0x0000adf3}, + {0x34, 0x00009df0}, {0x34, 0x00008ded}, + {0x34, 0x00007dea}, {0x34, 0x00006de7}, + {0x34, 0x000054ee}, {0x34, 0x000044eb}, + {0x34, 0x000034e8}, {0x34, 0x0000246b}, + {0x34, 0x00001468}, {0x34, 0x0000006d}, + {0x00, 0x00030159}, {0x84, 0x00068200}, + {0x86, 0x000000ce}, {0x87, 0x00048a00}, + {0x8e, 0x00065540}, {0x8f, 0x00088000}, + {0xef, 0x000020a0}, {0x3b, 0x000f02b0}, + {0x3b, 0x000ef7b0}, {0x3b, 0x000d4fb0}, + {0x3b, 0x000cf060}, {0x3b, 0x000b0090}, + {0x3b, 0x000a0080}, {0x3b, 0x00090080}, + {0x3b, 0x0008f780}, {0x3b, 0x000722b0}, + {0x3b, 0x0006f7b0}, {0x3b, 0x00054fb0}, + {0x3b, 0x0004f060}, {0x3b, 0x00030090}, + {0x3b, 0x00020080}, {0x3b, 0x00010080}, + {0x3b, 0x0000f780}, {0xef, 0x000000a0}, + {0x00, 0x00010159}, {0x18, 0x0000f407}, + {0xFE, 0x00000000}, {0xFE, 0x00000000}, + {0x1F, 0x00080003}, {0xFE, 0x00000000}, + {0xFE, 0x00000000}, {0x1E, 0x00000001}, + {0x1F, 0x00080000}, {0x00, 0x00033e60}, + {0xff, 0xffffffff} +}; + +#define PERENTRY 23 +#define RETRYSIZE 5 +#define RATESIZE 28 +#define TX_RPT2_ITEM_SIZE 8 + +static const u8 retry_penalty[PERENTRY][RETRYSIZE + 1] = { + {5, 4, 3, 2, 0, 3}, /* 92 , idx=0 */ + {6, 5, 4, 3, 0, 4}, /* 86 , idx=1 */ + {6, 5, 4, 2, 0, 4}, /* 81 , idx=2 */ + {8, 7, 6, 4, 0, 6}, /* 75 , idx=3 */ + {10, 9, 8, 6, 0, 8}, /* 71 , idx=4 */ + {10, 9, 8, 4, 0, 8}, /* 66 , idx=5 */ + {10, 9, 8, 2, 0, 8}, /* 62 , idx=6 */ + {10, 9, 8, 0, 0, 8}, /* 59 , idx=7 */ + {18, 17, 16, 8, 0, 16}, /* 53 , idx=8 */ + {26, 25, 24, 16, 0, 24}, /* 50 , idx=9 */ + {34, 33, 32, 24, 0, 32}, /* 47 , idx=0x0a */ + {34, 31, 28, 20, 0, 32}, /* 43 , idx=0x0b */ + {34, 31, 27, 18, 0, 32}, /* 40 , idx=0x0c */ + {34, 31, 26, 16, 0, 32}, /* 37 , idx=0x0d */ + {34, 30, 22, 16, 0, 32}, /* 32 , idx=0x0e */ + {34, 30, 24, 16, 0, 32}, /* 26 , idx=0x0f */ + {49, 46, 40, 16, 0, 48}, /* 20 , idx=0x10 */ + {49, 45, 32, 0, 0, 48}, /* 17 , idx=0x11 */ + {49, 45, 22, 18, 0, 48}, /* 15 , idx=0x12 */ + {49, 40, 24, 16, 0, 48}, /* 12 , idx=0x13 */ + {49, 32, 18, 12, 0, 48}, /* 9 , idx=0x14 */ + {49, 22, 18, 14, 0, 48}, /* 6 , idx=0x15 */ + {49, 16, 16, 0, 0, 48} /* 3, idx=0x16 */ +}; + +static const u8 pt_penalty[RETRYSIZE + 1] = {34, 31, 30, 24, 0, 32}; + +static const u8 retry_penalty_idx_normal[2][RATESIZE] = { + { /* RSSI>TH */ + 4, 4, 4, 5, + 4, 4, 5, 7, 7, 7, 8, 0x0a, + 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d, + 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f + }, + { /* RSSI<TH */ + 0x0a, 0x0a, 0x0b, 0x0c, + 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x13, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x13, + 9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13 + } +}; + +static const u8 retry_penalty_idx_cut_i[2][RATESIZE] = { + { /* RSSI>TH */ + 4, 4, 4, 5, + 4, 4, 5, 7, 7, 7, 8, 0x0a, + 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d, + 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f + }, + { /* RSSI<TH */ + 0x0a, 0x0a, 0x0b, 0x0c, + 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x13, + 0x06, 0x07, 0x08, 0x0d, 0x0e, 0x11, 0x11, 0x11, + 9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13 + } +}; + +static const u8 retry_penalty_up_idx_normal[RATESIZE] = { + 0x0c, 0x0d, 0x0d, 0x0f, + 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14, + 0x0f, 0x10, 0x10, 0x12, 0x12, 0x13, 0x14, 0x15, + 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15 +}; + +static const u8 retry_penalty_up_idx_cut_i[RATESIZE] = { + 0x0c, 0x0d, 0x0d, 0x0f, + 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14, + 0x0b, 0x0b, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, + 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15 +}; + +static const u8 rssi_threshold[RATESIZE] = { + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0x24, 0x26, 0x2a, + 0x18, 0x1a, 0x1d, 0x1f, 0x21, 0x27, 0x29, 0x2a, + 0, 0, 0, 0x1f, 0x23, 0x28, 0x2a, 0x2c +}; + +static const u16 n_threshold_high[RATESIZE] = { + 4, 4, 8, 16, + 24, 36, 48, 72, 96, 144, 192, 216, + 60, 80, 100, 160, 240, 400, 600, 800, + 300, 320, 480, 720, 1000, 1200, 1600, 2000 +}; + +static const u16 n_threshold_low[RATESIZE] = { + 2, 2, 4, 8, + 12, 18, 24, 36, 48, 72, 96, 108, + 30, 40, 50, 80, 120, 200, 300, 400, + 150, 160, 240, 360, 500, 600, 800, 1000 +}; + +static const u8 dropping_necessary[RATESIZE] = { + 1, 1, 1, 1, + 1, 2, 3, 4, 5, 6, 7, 8, + 1, 2, 3, 4, 5, 6, 7, 8, + 5, 6, 7, 8, 9, 10, 11, 12 +}; + +static const u8 pending_for_rate_up_fail[5] = {2, 10, 24, 40, 60}; + +static const u16 dynamic_tx_rpt_timing[6] = { + 0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12, 0x927c /* 200ms-1200ms */ +}; + +enum rtl8188e_tx_rpt_timing { + DEFAULT_TIMING = 0, + INCREASE_TIMING, + DECREASE_TIMING +}; + +static int rtl8188eu_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 sys_cfg, vendor; + int ret = 0; + + strscpy(priv->chip_name, "8188EU", sizeof(priv->chip_name)); + priv->rtl_chip = RTL8188E; + priv->rf_paths = 1; + priv->rx_paths = 1; + priv->tx_paths = 1; + priv->has_wifi = 1; + + sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK); + if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + return -EOPNOTSUPP; + } + + /* + * TODO: At a glance, I cut requires a different firmware, + * different initialisation tables, and no software rate + * control. The vendor driver is not configured to handle + * I cut chips by default. Are there any in the wild? + */ + if (priv->chip_cut == 8) { + dev_info(dev, "RTL8188EU cut I is not supported. Please complain about it at linux-wireless@vger.kernel.org.\n"); + return -EOPNOTSUPP; + } + + vendor = sys_cfg & SYS_CFG_VENDOR_ID; + rtl8xxxu_identify_vendor_1bit(priv, vendor); + + ret = rtl8xxxu_config_endpoints_no_sie(priv); + + return ret; +} + +static void rtl8188eu_config_channel(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + u32 val32, rsr; + u8 opmode; + int sec_ch_above, channel; + int i; + + opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE); + rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); + channel = hw->conf.chandef.chan->hw_value; + + switch (hw->conf.chandef.width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + opmode |= BW_OPMODE_20MHZ; + rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 &= ~FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); + val32 &= ~FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); + break; + case NL80211_CHAN_WIDTH_40: + if (hw->conf.chandef.center_freq1 > + hw->conf.chandef.chan->center_freq) { + sec_ch_above = 1; + channel += 2; + } else { + sec_ch_above = 0; + channel -= 2; + } + + opmode &= ~BW_OPMODE_20MHZ; + rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); + rsr &= ~RSR_RSC_BANDWIDTH_40M; + if (sec_ch_above) + rsr |= RSR_RSC_LOWER_SUB_CHANNEL; + else + rsr |= RSR_RSC_UPPER_SUB_CHANNEL; + rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 |= FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); + val32 |= FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); + + /* + * Set Control channel to upper or lower. These settings + * are required only for 40MHz + */ + val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM); + val32 &= ~CCK0_SIDEBAND; + if (!sec_ch_above) + val32 |= CCK0_SIDEBAND; + rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF); + val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */ + if (sec_ch_above) + val32 |= OFDM_LSTF_PRIME_CH_LOW; + else + val32 |= OFDM_LSTF_PRIME_CH_HIGH; + rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE); + val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL); + if (sec_ch_above) + val32 |= FPGA0_PS_UPPER_CHANNEL; + else + val32 |= FPGA0_PS_LOWER_CHANNEL; + rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32); + break; + + default: + break; + } + + for (i = RF_A; i < priv->rf_paths; i++) { + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); + u32p_replace_bits(&val32, channel, MODE_AG_CHANNEL_MASK); + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); + } + + for (i = RF_A; i < priv->rf_paths; i++) { + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); + val32 &= ~MODE_AG_BW_MASK; + if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40) + val32 |= MODE_AG_BW_40MHZ_8723B; + else + val32 |= MODE_AG_BW_20MHZ_8723B; + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); + } +} + +static void rtl8188eu_init_aggregation(struct rtl8xxxu_priv *priv) +{ + u8 agg_ctrl, usb_spec; + + usb_spec = rtl8xxxu_read8(priv, REG_USB_SPECIAL_OPTION); + usb_spec &= ~USB_SPEC_USB_AGG_ENABLE; + rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, usb_spec); + + agg_ctrl = rtl8xxxu_read8(priv, REG_TRXDMA_CTRL); + agg_ctrl &= ~TRXDMA_CTRL_RXDMA_AGG_EN; + rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl); +} + +static int rtl8188eu_parse_efuse(struct rtl8xxxu_priv *priv) +{ + struct rtl8188eu_efuse *efuse = &priv->efuse_wifi.efuse8188eu; + + if (efuse->rtl_id != cpu_to_le16(0x8129)) + return -EINVAL; + + ether_addr_copy(priv->mac_addr, efuse->mac_addr); + + memcpy(priv->cck_tx_power_index_A, efuse->tx_power_index_A.cck_base, + sizeof(efuse->tx_power_index_A.cck_base)); + + memcpy(priv->ht40_1s_tx_power_index_A, + efuse->tx_power_index_A.ht40_base, + sizeof(efuse->tx_power_index_A.ht40_base)); + + priv->default_crystal_cap = efuse->xtal_k & 0x3f; + + dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); + dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name); + dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial); + + return 0; +} + +static void rtl8188eu_reset_8051(struct rtl8xxxu_priv *priv) +{ + u16 sys_func; + + sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC); + sys_func &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); + + sys_func |= SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); +} + +static int rtl8188eu_load_firmware(struct rtl8xxxu_priv *priv) +{ + const char *fw_name; + int ret; + + fw_name = "rtlwifi/rtl8188eufw.bin"; + + ret = rtl8xxxu_load_firmware(priv, fw_name); + + return ret; +} + +static void rtl8188eu_init_phy_bb(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB | SYS_FUNC_DIO_RF; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + + /* + * Per vendor driver, run power sequence before init of RF + */ + val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB; + rtl8xxxu_write8(priv, REG_RF_CTRL, val8); + + val8 = SYS_FUNC_USBA | SYS_FUNC_USBD | + SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB; + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + rtl8xxxu_init_phy_regs(priv, rtl8188eu_phy_init_table); + rtl8xxxu_init_phy_regs(priv, rtl8188e_agc_table); +} + +static int rtl8188eu_init_phy_rf(struct rtl8xxxu_priv *priv) +{ + return rtl8xxxu_init_phy_rf(priv, rtl8188eu_radioa_init_table, RF_A); +} + +static int rtl8188eu_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_e94, reg_e9c; + int result = 0; + + /* Path A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x30008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x8214032a); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160000); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00462911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(10); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000)) + result |= 0x01; + + return result; +} + +static int rtl8188eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_ea4, reg_eac, reg_e94, reg_e9c, val32; + int result = 0; + + /* Leave IQK mode */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* Enable path A PA in TX IQK mode */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf117b); + + /* Enter IQK mode */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0x808000, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* TX IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x81004800); + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x30008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160804); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160000); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(10); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000)) + result |= 0x01; + else + goto out; + + val32 = 0x80007c00 | + (reg_e94 & 0x03ff0000) | ((reg_e9c >> 16) & 0x03ff); + rtl8xxxu_write32(priv, REG_TX_IQK, val32); + + /* Modify RX IQK mode table */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7ffa); + + /* Enter IQK mode */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0x808000, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* IQK setting */ + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* Path A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x30008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x10008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c05); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c05); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(10); + + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2); + + if (!(reg_eac & BIT(27)) && + ((reg_ea4 & 0x03ff0000) != 0x01320000) && + ((reg_eac & 0x03ff0000) != 0x00360000)) + result |= 0x02; + else + dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n", + __func__); + +out: + return result; +} + +static void rtl8188eu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, + int result[][8], int t) +{ + struct device *dev = &priv->udev->dev; + u32 i, val32; + int path_a_ok; + int retry = 2; + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, + REG_RX_WAIT_CCA, REG_TX_CCK_RFON, + REG_TX_CCK_BBON, REG_TX_OFDM_RFON, + REG_TX_OFDM_BBON, REG_TX_TO_RX, + REG_TX_TO_TX, REG_RX_CCK, + REG_RX_OFDM, REG_RX_WAIT_RIFS, + REG_RX_TO_RX, REG_STANDBY, + REG_SLEEP, REG_PMPD_ANAEN + }; + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + REG_TXPAUSE, REG_BEACON_CTRL, + REG_BEACON_CTRL_1, REG_GPIO_MUXCFG + }; + static const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, + REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, + REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, + REG_FPGA0_XB_RF_INT_OE, REG_CCK0_AFE_SETTING + }; + + /* + * Note: IQ calibration must be performed after loading + * PHY_REG.txt , and radio_a, radio_b.txt + */ + + if (t == 0) { + /* Save ADDA parameters, turn Path A ADDA on */ + rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup, + RTL8XXXU_ADDA_REGS); + rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + rtl8xxxu_save_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + } + + rtl8xxxu_path_adda_on(priv, adda_regs, true); + + if (t == 0) { + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1); + priv->pi_enabled = u32_get_bits(val32, FPGA0_HSSI_PARM1_PI); + } + + if (!priv->pi_enabled) { + /* Switch BB to PI mode to do IQ Calibration. */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); + rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100); + } + + /* MAC settings */ + rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup); + + val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING); + u32p_replace_bits(&val32, 0xf, 0x0f000000); + rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32); + + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000); + + if (!priv->no_pape) { + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL); + val32 |= (FPGA0_RF_PAPE | + (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT)); + rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32); + } + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE); + val32 &= ~BIT(10); + rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32); + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE); + val32 &= ~BIT(10); + rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32); + + /* Page B init */ + rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x0f600000); + + /* IQ calibration setting */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0x808000, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x81004800); + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8188eu_iqk_path_a(priv); + if (path_a_ok == 0x01) { + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_BEFORE_IQK_A); + result[t][0] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_AFTER_IQK_A); + result[t][1] = (val32 >> 16) & 0x3ff; + break; + } + } + + if (!path_a_ok) + dev_dbg(dev, "%s: Path A TX IQK failed!\n", __func__); + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8188eu_rx_iqk_path_a(priv); + if (path_a_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_BEFORE_IQK_A_2); + result[t][2] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_AFTER_IQK_A_2); + result[t][3] = (val32 >> 16) & 0x3ff; + + break; + } + } + + if (!path_a_ok) + dev_dbg(dev, "%s: Path A RX IQK failed!\n", __func__); + + /* Back to BB mode, load original value */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + if (t == 0) + return; + + if (!priv->pi_enabled) { + /* Switch back BB to SI mode after finishing IQ Calibration */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000000); + rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000000); + } + + /* Reload ADDA power saving parameters */ + rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup, + RTL8XXXU_ADDA_REGS); + + /* Reload MAC parameters */ + rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + + /* Reload BB parameters */ + rtl8xxxu_restore_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + + /* Restore RX initial gain */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00032ed3); + + /* Load 0xe30 IQC default value */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00); +} + +static void rtl8188eu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + int result[4][8]; /* last is final result */ + int i, candidate; + bool path_a_ok; + u32 reg_e94, reg_e9c, reg_ea4, reg_eac; + u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc; + bool simu; + + memset(result, 0, sizeof(result)); + result[3][0] = 0x100; + result[3][2] = 0x100; + result[3][4] = 0x100; + result[3][6] = 0x100; + + candidate = -1; + + path_a_ok = false; + + for (i = 0; i < 3; i++) { + rtl8188eu_phy_iqcalibrate(priv, result, i); + + if (i == 1) { + simu = rtl8xxxu_simularity_compare(priv, + result, 0, 1); + if (simu) { + candidate = 0; + break; + } + } + + if (i == 2) { + simu = rtl8xxxu_simularity_compare(priv, + result, 0, 2); + if (simu) { + candidate = 0; + break; + } + + simu = rtl8xxxu_simularity_compare(priv, + result, 1, 2); + if (simu) + candidate = 1; + else + candidate = 3; + } + } + + if (candidate >= 0) { + reg_e94 = result[candidate][0]; + priv->rege94 = reg_e94; + reg_e9c = result[candidate][1]; + priv->rege9c = reg_e9c; + reg_ea4 = result[candidate][2]; + reg_eac = result[candidate][3]; + reg_eb4 = result[candidate][4]; + priv->regeb4 = reg_eb4; + reg_ebc = result[candidate][5]; + priv->regebc = reg_ebc; + reg_ec4 = result[candidate][6]; + reg_ecc = result[candidate][7]; + dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate); + dev_dbg(dev, + "%s: e94=%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x ecc=%x\n", + __func__, reg_e94, reg_e9c, reg_ea4, reg_eac, + reg_eb4, reg_ebc, reg_ec4, reg_ecc); + path_a_ok = true; + } else { + reg_e94 = 0x100; + reg_eb4 = 0x100; + priv->rege94 = 0x100; + priv->regeb4 = 0x100; + reg_e9c = 0x0; + reg_ebc = 0x0; + priv->rege9c = 0x0; + priv->regebc = 0x0; + } + + if (reg_e94 && candidate >= 0) + rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result, + candidate, (reg_ea4 == 0)); + + rtl8xxxu_save_regs(priv, rtl8xxxu_iqk_phy_iq_bb_reg, + priv->bb_recovery_backup, RTL8XXXU_BB_REGS); +} + +static void rtl8188e_disabled_to_emu(struct rtl8xxxu_priv *priv) +{ + u16 val16; + + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~(APS_FSMCO_HW_SUSPEND | APS_FSMCO_PCIE); + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); +} + +static int rtl8188e_emu_to_active(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u32 val32; + u16 val16; + int count, ret = 0; + + /* wait till 0x04[17] = 1 power ready*/ + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if (val32 & BIT(17)) + break; + + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* reset baseband */ + val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); + val8 &= ~(SYS_FUNC_BBRSTB | SYS_FUNC_BB_GLB_RSTN); + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + /*0x24[23] = 2b'01 schmit trigger */ + val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); + val32 |= BIT(23); + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); + + /* 0x04[15] = 0 disable HWPDN (control by DRV)*/ + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~APS_FSMCO_HW_POWERDOWN; + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + /*0x04[12:11] = 2b'00 disable WL suspend*/ + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~(APS_FSMCO_HW_SUSPEND | APS_FSMCO_PCIE); + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + /* set, then poll until 0 */ + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + val32 |= APS_FSMCO_MAC_ENABLE; + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) { + ret = 0; + break; + } + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* LDO normal mode*/ + val8 = rtl8xxxu_read8(priv, REG_LPLDO_CTRL); + val8 &= ~BIT(4); + rtl8xxxu_write8(priv, REG_LPLDO_CTRL, val8); + +exit: + return ret; +} + +static int rtl8188eu_active_to_emu(struct rtl8xxxu_priv *priv) +{ + u8 val8; + + /* Turn off RF */ + val8 = rtl8xxxu_read8(priv, REG_RF_CTRL); + val8 &= ~RF_ENABLE; + rtl8xxxu_write8(priv, REG_RF_CTRL, val8); + + /* LDO Sleep mode */ + val8 = rtl8xxxu_read8(priv, REG_LPLDO_CTRL); + val8 |= BIT(4); + rtl8xxxu_write8(priv, REG_LPLDO_CTRL, val8); + + return 0; +} + +static int rtl8188eu_emu_to_disabled(struct rtl8xxxu_priv *priv) +{ + u32 val32; + u16 val16; + u8 val8; + + val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); + val32 |= BIT(23); + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); + + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~APS_FSMCO_PCIE; + val16 |= APS_FSMCO_HW_SUSPEND; + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x00); + + val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG + 1); + val8 &= ~BIT(4); + rtl8xxxu_write8(priv, REG_GPIO_MUXCFG + 1, val8); + + /* Set USB suspend enable local register 0xfe10[4]=1 */ + val8 = rtl8xxxu_read8(priv, 0xfe10); + val8 |= BIT(4); + rtl8xxxu_write8(priv, 0xfe10, val8); + + return 0; +} + +static int rtl8188eu_active_to_lps(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u8 val8; + u16 val16; + u32 val32; + int retry, retval; + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x7f); + + retry = 100; + retval = -EBUSY; + /* Poll 32 bit wide REG_SCH_TX_CMD for 0 to ensure no TX is pending. */ + do { + val32 = rtl8xxxu_read32(priv, REG_SCH_TX_CMD); + if (!val32) { + retval = 0; + break; + } + } while (retry--); + + if (!retry) { + dev_warn(dev, "Failed to flush TX queue\n"); + retval = -EBUSY; + goto out; + } + + /* Disable CCK and OFDM, clock gated */ + val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); + val8 &= ~SYS_FUNC_BBRSTB; + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + udelay(2); + + /* Reset MAC TRX */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= 0xff; + val16 &= ~(CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE | CR_SECURITY_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + + val8 = rtl8xxxu_read8(priv, REG_DUAL_TSF_RST); + val8 |= DUAL_TSF_TX_OK; + rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, val8); + +out: + return retval; +} + +static int rtl8188eu_power_on(struct rtl8xxxu_priv *priv) +{ + u16 val16; + int ret; + + rtl8188e_disabled_to_emu(priv); + + ret = rtl8188e_emu_to_active(priv); + if (ret) + goto exit; + + /* + * Enable MAC DMA/WMAC/SCHEDULE/SEC block + * Set CR bit10 to enable 32k calibration. + * We do not set CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE here + * due to a hardware bug in the 88E, requiring those to be + * set after REG_TRXFF_BNDY is set. If not the RXFF bundary + * will get set to a larger buffer size than the real buffer + * size. + */ + val16 = (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE | + CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | + CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE | + CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + +exit: + return ret; +} + +static void rtl8188eu_power_off(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + + rtl8xxxu_flush_fifo(priv); + + val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL); + val8 &= ~TX_REPORT_CTRL_TIMER_ENABLE; + rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8); + + /* Turn off RF */ + rtl8xxxu_write8(priv, REG_RF_CTRL, 0x00); + + rtl8188eu_active_to_lps(priv); + + /* Reset Firmware if running in RAM */ + if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL) + rtl8xxxu_firmware_self_reset(priv); + + /* Reset MCU */ + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + + /* Reset MCU ready status */ + rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); + + /* 32K_CTRL looks to be very 8188e specific */ + val8 = rtl8xxxu_read8(priv, REG_32K_CTRL); + val8 &= ~BIT(0); + rtl8xxxu_write8(priv, REG_32K_CTRL, val8); + + rtl8188eu_active_to_emu(priv); + rtl8188eu_emu_to_disabled(priv); + + /* Reset MCU IO Wrapper */ + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 &= ~BIT(3); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 |= BIT(3); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + + /* Vendor driver refers to GPIO_IN */ + val8 = rtl8xxxu_read8(priv, REG_GPIO_PIN_CTRL); + /* Vendor driver refers to GPIO_OUT */ + rtl8xxxu_write8(priv, REG_GPIO_PIN_CTRL + 1, val8); + rtl8xxxu_write8(priv, REG_GPIO_PIN_CTRL + 2, 0xff); + + val8 = rtl8xxxu_read8(priv, REG_GPIO_IO_SEL); + rtl8xxxu_write8(priv, REG_GPIO_IO_SEL, val8 << 4); + val8 = rtl8xxxu_read8(priv, REG_GPIO_IO_SEL + 1); + rtl8xxxu_write8(priv, REG_GPIO_IO_SEL + 1, val8 | 0x0f); + + /* + * Set LNA, TRSW, EX_PA Pin to output mode + * Referred to as REG_BB_PAD_CTRL in 8188eu vendor driver + */ + rtl8xxxu_write32(priv, REG_PAD_CTRL1, 0x00080808); + + rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x00); + + rtl8xxxu_write32(priv, REG_GPIO_MUXCFG, 0x00000000); +} + +static void rtl8188e_enable_rf(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + rtl8xxxu_write8(priv, REG_RF_CTRL, RF_ENABLE | RF_RSTB | RF_SDMRSTB); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK); + val32 |= OFDM_RF_PATH_RX_A | OFDM_RF_PATH_TX_A; + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); +} + +static void rtl8188e_disable_rf(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~OFDM_RF_PATH_TX_MASK; + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + /* Power down RF module */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0); + + rtl8188eu_active_to_emu(priv); +} + +static void rtl8188e_usb_quirks(struct rtl8xxxu_priv *priv) +{ + u16 val16; + + /* + * Technically this is not a USB quirk, but a chip quirk. + * This has to be done after REG_TRXFF_BNDY is set, see + * rtl8188eu_power_on() for details. + */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= (CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + + rtl8xxxu_gen2_usb_quirks(priv); + + /* Pre-TX enable WEP/TKIP security */ + rtl8xxxu_write8(priv, REG_EARLY_MODE_CONTROL_8188E + 3, 0x01); +} + +static s8 rtl8188e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) +{ + /* only use lna 0/1/2/3/7 */ + static const s8 lna_gain_table_0[8] = {17, -1, -13, -29, -32, -35, -38, -41}; + /* only use lna 3/7 */ + static const s8 lna_gain_table_1[8] = {29, 20, 12, 3, -6, -15, -24, -33}; + + s8 rx_pwr_all = 0x00; + u8 vga_idx, lna_idx; + s8 lna_gain = 0; + + lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK); + vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK); + + if (priv->chip_cut >= 8) /* cut I */ /* SMIC */ + lna_gain = lna_gain_table_0[lna_idx]; + else /* TSMC */ + lna_gain = lna_gain_table_1[lna_idx]; + + rx_pwr_all = lna_gain - (2 * vga_idx); + + return rx_pwr_all; +} + +static void rtl8188e_set_tx_rpt_timing(struct rtl8xxxu_ra_info *ra, u8 timing) +{ + u8 idx; + + for (idx = 0; idx < 5; idx++) + if (dynamic_tx_rpt_timing[idx] == ra->rpt_time) + break; + + if (timing == DEFAULT_TIMING) { + idx = 0; /* 200ms */ + } else if (timing == INCREASE_TIMING) { + if (idx < 5) + idx++; + } else if (timing == DECREASE_TIMING) { + if (idx > 0) + idx--; + } + + ra->rpt_time = dynamic_tx_rpt_timing[idx]; +} + +static void rtl8188e_rate_down(struct rtl8xxxu_ra_info *ra) +{ + u8 rate_id = ra->pre_rate; + u8 lowest_rate = ra->lowest_rate; + u8 highest_rate = ra->highest_rate; + s8 i; + + if (rate_id > highest_rate) { + rate_id = highest_rate; + } else if (ra->rate_sgi) { + ra->rate_sgi = 0; + } else if (rate_id > lowest_rate) { + if (rate_id > 0) { + for (i = rate_id - 1; i >= lowest_rate; i--) { + if (ra->ra_use_rate & BIT(i)) { + rate_id = i; + goto rate_down_finish; + } + } + } + } else if (rate_id <= lowest_rate) { + rate_id = lowest_rate; + } + +rate_down_finish: + if (ra->ra_waiting_counter == 1) { + ra->ra_waiting_counter++; + ra->ra_pending_counter++; + } else if (ra->ra_waiting_counter > 1) { + ra->ra_waiting_counter = 0; + ra->ra_pending_counter = 0; + } + + if (ra->ra_pending_counter >= 4) + ra->ra_pending_counter = 4; + + ra->ra_drop_after_down = 1; + + ra->decision_rate = rate_id; + + rtl8188e_set_tx_rpt_timing(ra, DECREASE_TIMING); +} + +static void rtl8188e_rate_up(struct rtl8xxxu_ra_info *ra) +{ + u8 rate_id = ra->pre_rate; + u8 highest_rate = ra->highest_rate; + u8 i; + + if (ra->ra_waiting_counter == 1) { + ra->ra_waiting_counter = 0; + ra->ra_pending_counter = 0; + } else if (ra->ra_waiting_counter > 1) { + ra->pre_rssi_sta_ra = ra->rssi_sta_ra; + goto rate_up_finish; + } + + rtl8188e_set_tx_rpt_timing(ra, DEFAULT_TIMING); + + if (rate_id < highest_rate) { + for (i = rate_id + 1; i <= highest_rate; i++) { + if (ra->ra_use_rate & BIT(i)) { + rate_id = i; + goto rate_up_finish; + } + } + } else if (rate_id == highest_rate) { + if (ra->sgi_enable && !ra->rate_sgi) + ra->rate_sgi = 1; + else if (!ra->sgi_enable) + ra->rate_sgi = 0; + } else { /* rate_id > ra->highest_rate */ + rate_id = highest_rate; + } + +rate_up_finish: + if (ra->ra_waiting_counter == (4 + pending_for_rate_up_fail[ra->ra_pending_counter])) + ra->ra_waiting_counter = 0; + else + ra->ra_waiting_counter++; + + ra->decision_rate = rate_id; +} + +static void rtl8188e_reset_ra_counter(struct rtl8xxxu_ra_info *ra) +{ + u8 rate_id = ra->decision_rate; + + ra->nsc_up = (n_threshold_high[rate_id] + n_threshold_low[rate_id]) >> 1; + ra->nsc_down = (n_threshold_high[rate_id] + n_threshold_low[rate_id]) >> 1; +} + +static void rtl8188e_rate_decision(struct rtl8xxxu_ra_info *ra) +{ + struct rtl8xxxu_priv *priv = container_of(ra, struct rtl8xxxu_priv, ra_info); + const u8 *retry_penalty_idx_0; + const u8 *retry_penalty_idx_1; + const u8 *retry_penalty_up_idx; + u8 rate_id, penalty_id1, penalty_id2; + int i; + + if (ra->total == 0) + return; + + if (ra->ra_drop_after_down) { + ra->ra_drop_after_down--; + + rtl8188e_reset_ra_counter(ra); + + return; + } + + if (priv->chip_cut == 8) { /* cut I */ + retry_penalty_idx_0 = retry_penalty_idx_cut_i[0]; + retry_penalty_idx_1 = retry_penalty_idx_cut_i[1]; + retry_penalty_up_idx = retry_penalty_up_idx_cut_i; + } else { + retry_penalty_idx_0 = retry_penalty_idx_normal[0]; + retry_penalty_idx_1 = retry_penalty_idx_normal[1]; + retry_penalty_up_idx = retry_penalty_up_idx_normal; + } + + if (ra->rssi_sta_ra < (ra->pre_rssi_sta_ra - 3) || + ra->rssi_sta_ra > (ra->pre_rssi_sta_ra + 3)) { + ra->pre_rssi_sta_ra = ra->rssi_sta_ra; + ra->ra_waiting_counter = 0; + ra->ra_pending_counter = 0; + } + + /* Start RA decision */ + if (ra->pre_rate > ra->highest_rate) + rate_id = ra->highest_rate; + else + rate_id = ra->pre_rate; + + /* rate down */ + if (ra->rssi_sta_ra > rssi_threshold[rate_id]) + penalty_id1 = retry_penalty_idx_0[rate_id]; + else + penalty_id1 = retry_penalty_idx_1[rate_id]; + + for (i = 0; i < 5; i++) + ra->nsc_down += ra->retry[i] * retry_penalty[penalty_id1][i]; + + if (ra->nsc_down > (ra->total * retry_penalty[penalty_id1][5])) + ra->nsc_down -= ra->total * retry_penalty[penalty_id1][5]; + else + ra->nsc_down = 0; + + /* rate up */ + penalty_id2 = retry_penalty_up_idx[rate_id]; + + for (i = 0; i < 5; i++) + ra->nsc_up += ra->retry[i] * retry_penalty[penalty_id2][i]; + + if (ra->nsc_up > (ra->total * retry_penalty[penalty_id2][5])) + ra->nsc_up -= ra->total * retry_penalty[penalty_id2][5]; + else + ra->nsc_up = 0; + + if (ra->nsc_down < n_threshold_low[rate_id] || + ra->drop > dropping_necessary[rate_id]) { + rtl8188e_rate_down(ra); + + rtl8xxxu_update_ra_report(&priv->ra_report, ra->decision_rate, + ra->rate_sgi, priv->ra_report.txrate.bw); + } else if (ra->nsc_up > n_threshold_high[rate_id]) { + rtl8188e_rate_up(ra); + + rtl8xxxu_update_ra_report(&priv->ra_report, ra->decision_rate, + ra->rate_sgi, priv->ra_report.txrate.bw); + } + + if (ra->decision_rate == ra->pre_rate) + ra->dynamic_tx_rpt_timing_counter++; + else + ra->dynamic_tx_rpt_timing_counter = 0; + + if (ra->dynamic_tx_rpt_timing_counter >= 4) { + /* Rate didn't change 4 times, extend RPT timing */ + rtl8188e_set_tx_rpt_timing(ra, INCREASE_TIMING); + ra->dynamic_tx_rpt_timing_counter = 0; + } + + ra->pre_rate = ra->decision_rate; + + rtl8188e_reset_ra_counter(ra); +} + +static void rtl8188e_power_training_try_state(struct rtl8xxxu_ra_info *ra) +{ + ra->pt_try_state = 0; + switch (ra->pt_mode_ss) { + case 3: + if (ra->decision_rate >= DESC_RATE_MCS13) + ra->pt_try_state = 1; + break; + case 2: + if (ra->decision_rate >= DESC_RATE_MCS5) + ra->pt_try_state = 1; + break; + case 1: + if (ra->decision_rate >= DESC_RATE_48M) + ra->pt_try_state = 1; + break; + case 0: + if (ra->decision_rate >= DESC_RATE_11M) + ra->pt_try_state = 1; + break; + default: + break; + } + + if (ra->rssi_sta_ra < 48) { + ra->pt_stage = 0; + } else if (ra->pt_try_state == 1) { + if ((ra->pt_stop_count >= 10) || + (ra->pt_pre_rssi > ra->rssi_sta_ra + 5) || + (ra->pt_pre_rssi < ra->rssi_sta_ra - 5) || + (ra->decision_rate != ra->pt_pre_rate)) { + if (ra->pt_stage == 0) + ra->pt_stage = 1; + else if (ra->pt_stage == 1) + ra->pt_stage = 3; + else + ra->pt_stage = 5; + + ra->pt_pre_rssi = ra->rssi_sta_ra; + ra->pt_stop_count = 0; + } else { + ra->ra_stage = 0; + ra->pt_stop_count++; + } + } else { + ra->pt_stage = 0; + ra->ra_stage = 0; + } + + ra->pt_pre_rate = ra->decision_rate; + + /* TODO: implement the "false alarm" statistics for this */ + /* Disable power training when noisy environment */ + /* if (p_dm_odm->is_disable_power_training) { */ + if (1) { + ra->pt_stage = 0; + ra->ra_stage = 0; + ra->pt_stop_count = 0; + } +} + +static void rtl8188e_power_training_decision(struct rtl8xxxu_ra_info *ra) +{ + u8 temp_stage; + u32 numsc; + u32 num_total; + u8 stage_id; + u8 j; + + numsc = 0; + num_total = ra->total * pt_penalty[5]; + for (j = 0; j <= 4; j++) { + numsc += ra->retry[j] * pt_penalty[j]; + + if (numsc > num_total) + break; + } + + j >>= 1; + temp_stage = (ra->pt_stage + 1) >> 1; + if (temp_stage > j) + stage_id = temp_stage - j; + else + stage_id = 0; + + ra->pt_smooth_factor = (ra->pt_smooth_factor >> 1) + + (ra->pt_smooth_factor >> 2) + + stage_id * 16 + 2; + if (ra->pt_smooth_factor > 192) + ra->pt_smooth_factor = 192; + stage_id = ra->pt_smooth_factor >> 6; + temp_stage = stage_id * 2; + if (temp_stage != 0) + temp_stage--; + if (ra->drop > 3) + temp_stage = 0; + ra->pt_stage = temp_stage; +} + +void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *skb) +{ + u32 *_rx_desc = (u32 *)(skb->data - sizeof(struct rtl8xxxu_rxdesc16)); + struct rtl8xxxu_rxdesc16 *rx_desc = (struct rtl8xxxu_rxdesc16 *)_rx_desc; + struct device *dev = &priv->udev->dev; + struct rtl8xxxu_ra_info *ra = &priv->ra_info; + u32 tx_rpt_len = rx_desc->pktlen & 0x3ff; + u32 items = tx_rpt_len / TX_RPT2_ITEM_SIZE; + u64 macid_valid = ((u64)_rx_desc[5] << 32) | _rx_desc[4]; + u32 macid; + u8 *rpt = skb->data; + bool valid; + u16 min_rpt_time = 0x927c; + + dev_dbg(dev, "%s: len: %d items: %d\n", __func__, tx_rpt_len, items); + + for (macid = 0; macid < items; macid++) { + valid = false; + + if (macid < 64) + valid = macid_valid & BIT(macid); + + if (valid) { + ra->retry[0] = le16_to_cpu(*(__le16 *)rpt); + ra->retry[1] = rpt[2]; + ra->retry[2] = rpt[3]; + ra->retry[3] = rpt[4]; + ra->retry[4] = rpt[5]; + ra->drop = rpt[6]; + ra->total = ra->retry[0] + ra->retry[1] + ra->retry[2] + + ra->retry[3] + ra->retry[4] + ra->drop; + + if (ra->total > 0) { + if (ra->ra_stage < 5) + rtl8188e_rate_decision(ra); + else if (ra->ra_stage == 5) + rtl8188e_power_training_try_state(ra); + else /* ra->ra_stage == 6 */ + rtl8188e_power_training_decision(ra); + + if (ra->ra_stage <= 5) + ra->ra_stage++; + else + ra->ra_stage = 0; + } + } else if (macid == 0) { + dev_warn(dev, "%s: TX report item 0 not valid\n", __func__); + } + + dev_dbg(dev, "%s: valid: %d retry: %d %d %d %d %d drop: %d\n", + __func__, valid, + ra->retry[0], ra->retry[1], ra->retry[2], + ra->retry[3], ra->retry[4], ra->drop); + + if (min_rpt_time > ra->rpt_time) + min_rpt_time = ra->rpt_time; + + rpt += TX_RPT2_ITEM_SIZE; + + /* + * We only use macid 0, so only the first item is relevant. + * AP mode will use more of them if it's ever implemented. + */ + break; + } + + if (min_rpt_time != ra->pre_min_rpt_time) { + rtl8xxxu_write16(priv, REG_TX_REPORT_TIME, min_rpt_time); + ra->pre_min_rpt_time = min_rpt_time; + } +} + +static void rtl8188e_arfb_refresh(struct rtl8xxxu_ra_info *ra) +{ + s8 i; + + ra->ra_use_rate = ra->rate_mask; + + /* Highest rate */ + if (ra->ra_use_rate) { + for (i = RATESIZE; i >= 0; i--) { + if (ra->ra_use_rate & BIT(i)) { + ra->highest_rate = i; + break; + } + } + } else { + ra->highest_rate = 0; + } + + /* Lowest rate */ + if (ra->ra_use_rate) { + for (i = 0; i < RATESIZE; i++) { + if (ra->ra_use_rate & BIT(i)) { + ra->lowest_rate = i; + break; + } + } + } else { + ra->lowest_rate = 0; + } + + if (ra->highest_rate > DESC_RATE_MCS7) + ra->pt_mode_ss = 3; + else if (ra->highest_rate > DESC_RATE_54M) + ra->pt_mode_ss = 2; + else if (ra->highest_rate > DESC_RATE_11M) + ra->pt_mode_ss = 1; + else + ra->pt_mode_ss = 0; +} + +static void +rtl8188e_update_rate_mask(struct rtl8xxxu_priv *priv, + u32 ramask, u8 rateid, int sgi, int txbw_40mhz) +{ + struct rtl8xxxu_ra_info *ra = &priv->ra_info; + + ra->rate_id = rateid; + ra->rate_mask = ramask; + ra->sgi_enable = sgi; + + rtl8188e_arfb_refresh(ra); +} + +static void rtl8188e_ra_set_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi) +{ + priv->ra_info.rssi_sta_ra = rssi; +} + +void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra) +{ + ra->decision_rate = DESC_RATE_MCS7; + ra->pre_rate = DESC_RATE_MCS7; + ra->highest_rate = DESC_RATE_MCS7; + ra->lowest_rate = 0; + ra->rate_id = 0; + ra->rate_mask = 0xfffff; + ra->rssi_sta_ra = 0; + ra->pre_rssi_sta_ra = 0; + ra->sgi_enable = 0; + ra->ra_use_rate = 0xfffff; + ra->nsc_down = (n_threshold_high[DESC_RATE_MCS7] + n_threshold_low[DESC_RATE_MCS7]) / 2; + ra->nsc_up = (n_threshold_high[DESC_RATE_MCS7] + n_threshold_low[DESC_RATE_MCS7]) / 2; + ra->rate_sgi = 0; + ra->rpt_time = 0x927c; + ra->drop = 0; + ra->retry[0] = 0; + ra->retry[1] = 0; + ra->retry[2] = 0; + ra->retry[3] = 0; + ra->retry[4] = 0; + ra->total = 0; + ra->ra_waiting_counter = 0; + ra->ra_pending_counter = 0; + ra->ra_drop_after_down = 0; + + ra->pt_try_state = 0; + ra->pt_stage = 5; + ra->pt_smooth_factor = 192; + ra->pt_stop_count = 0; + ra->pt_pre_rate = 0; + ra->pt_pre_rssi = 0; + ra->pt_mode_ss = 0; + ra->ra_stage = 0; +} + +struct rtl8xxxu_fileops rtl8188eu_fops = { + .identify_chip = rtl8188eu_identify_chip, + .parse_efuse = rtl8188eu_parse_efuse, + .load_firmware = rtl8188eu_load_firmware, + .power_on = rtl8188eu_power_on, + .power_off = rtl8188eu_power_off, + .reset_8051 = rtl8188eu_reset_8051, + .llt_init = rtl8xxxu_init_llt_table, + .init_phy_bb = rtl8188eu_init_phy_bb, + .init_phy_rf = rtl8188eu_init_phy_rf, + .phy_lc_calibrate = rtl8723a_phy_lc_calibrate, + .phy_iq_calibrate = rtl8188eu_phy_iq_calibrate, + .config_channel = rtl8188eu_config_channel, + .parse_rx_desc = rtl8xxxu_parse_rxdesc16, + .init_aggregation = rtl8188eu_init_aggregation, + .enable_rf = rtl8188e_enable_rf, + .disable_rf = rtl8188e_disable_rf, + .usb_quirks = rtl8188e_usb_quirks, + .set_tx_power = rtl8188f_set_tx_power, + .update_rate_mask = rtl8188e_update_rate_mask, + .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8188e_ra_set_rssi, + .fill_txdesc = rtl8xxxu_fill_txdesc_v3, + .set_crystal_cap = rtl8188f_set_crystal_cap, + .cck_rssi = rtl8188e_cck_rssi, + .writeN_block_size = 128, + .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16), + .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), + .has_tx_report = 1, + .gen2_thermal_meter = 1, + .adda_1t_init = 0x0b1b25a0, + .adda_1t_path_on = 0x0bdb25a0, + /* + * Use 9K for 8188e normal chip + * Max RX buffer = 10K - max(TxReportSize(64*8), WOLPattern(16*24)) + */ + .trxff_boundary = 0x25ff, + .pbp_rx = PBP_PAGE_SIZE_128, + .pbp_tx = PBP_PAGE_SIZE_128, + .mactable = rtl8188e_mac_init_table, + .total_page_num = TX_TOTAL_PAGE_NUM_8188E, + .page_num_hi = TX_PAGE_NUM_HI_PQ_8188E, + .page_num_lo = TX_PAGE_NUM_LO_PQ_8188E, + .page_num_norm = TX_PAGE_NUM_NORM_PQ_8188E, + .last_llt_entry = 175, +}; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index 2c4f403ba68f..af6e2c8a5025 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -370,7 +370,7 @@ static void rtl8188f_channel_to_group(int channel, int *group, int *cck_group) *cck_group = *group; } -static void +void rtl8188f_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) { u32 val32, ofdm, mcs; @@ -716,7 +716,6 @@ static void rtl8188fu_init_statistics(struct rtl8xxxu_priv *priv) static int rtl8188fu_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8188fu_efuse *efuse = &priv->efuse_wifi.efuse8188fu; - int i; if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; @@ -738,22 +737,12 @@ static int rtl8188fu_parse_efuse(struct rtl8xxxu_priv *priv) dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.7s\n", efuse->device_name); - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { - unsigned char *raw = priv->efuse_wifi.raw; - - dev_info(&priv->udev->dev, - "%s: dumping efuse (0x%02zx bytes):\n", - __func__, sizeof(struct rtl8188fu_efuse)); - for (i = 0; i < sizeof(struct rtl8188fu_efuse); i += 8) - dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); - } - return 0; } static int rtl8188fu_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; fw_name = "rtlwifi/rtl8188fufw.bin"; @@ -1122,7 +1111,7 @@ static void rtl8188fu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, if (t == 0) { val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1); - priv->pi_enabled = val32 & FPGA0_HSSI_PARM1_PI; + priv->pi_enabled = u32_get_bits(val32, FPGA0_HSSI_PARM1_PI); } /* save RF path */ @@ -1662,7 +1651,7 @@ static void rtl8188f_usb_quirks(struct rtl8xxxu_priv *priv) #define XTAL1 GENMASK(22, 17) #define XTAL0 GENMASK(16, 11) -static void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) +void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) { struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking; u32 val32; @@ -1693,8 +1682,8 @@ static s8 rtl8188f_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) s8 rx_pwr_all = 0x00; u8 vga_idx, lna_idx; - lna_idx = (cck_agc_rpt & 0xE0) >> 5; - vga_idx = cck_agc_rpt & 0x1F; + lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK); + vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK); switch (lna_idx) { case 7: @@ -1743,6 +1732,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .set_tx_power = rtl8188f_set_tx_power, .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8xxxu_gen2_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, .set_crystal_cap = rtl8188f_set_crystal_cap, .cck_rssi = rtl8188f_cck_rssi, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c index 3bef9ffc8b02..e61d65c3579b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c @@ -386,7 +386,7 @@ out: static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; if (!priv->vendor_umc) @@ -404,7 +404,6 @@ static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv) static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8192cu_efuse *efuse = &priv->efuse_wifi.efuse8192; - int i; if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; @@ -457,15 +456,6 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) priv->power_base = &rtl8188r_power_base; } - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { - unsigned char *raw = priv->efuse_wifi.raw; - - dev_info(&priv->udev->dev, - "%s: dumping efuse (0x%02zx bytes):\n", - __func__, sizeof(struct rtl8192cu_efuse)); - for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) - dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); - } return 0; } @@ -619,6 +609,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = { .set_tx_power = rtl8xxxu_gen1_set_tx_power, .update_rate_mask = rtl8xxxu_update_rate_mask, .report_connect = rtl8xxxu_gen1_report_connect, + .report_rssi = rtl8xxxu_gen1_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v1, .cck_rssi = rtl8723a_cck_rssi, .writeN_block_size = 128, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index a7d76693c02d..4a1c9bcafe31 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -704,21 +704,12 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) rtl8192eu_log_next_device_info(priv, "Product", efuse->device_info, &record_offset); rtl8192eu_log_next_device_info(priv, "Serial", efuse->device_info, &record_offset); - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { - unsigned char *raw = priv->efuse_wifi.raw; - - dev_info(&priv->udev->dev, - "%s: dumping efuse (0x%02zx bytes):\n", - __func__, sizeof(struct rtl8192eu_efuse)); - for (i = 0; i < sizeof(struct rtl8192eu_efuse); i += 8) - dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); - } return 0; } static int rtl8192eu_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; fw_name = "rtlwifi/rtl8192eu_nic.bin"; @@ -1744,6 +1735,11 @@ static void rtl8192e_enable_rf(struct rtl8xxxu_priv *priv) val8 = rtl8xxxu_read8(priv, REG_PAD_CTRL1); val8 &= ~BIT(0); rtl8xxxu_write8(priv, REG_PAD_CTRL1, val8); + + /* + * Fix transmission failure of rtl8192e. + */ + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); } static s8 rtl8192e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) @@ -1755,8 +1751,8 @@ static s8 rtl8192e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) u8 vga_idx, lna_idx; s8 lna_gain = 0; - lna_idx = (cck_agc_rpt & 0xE0) >> 5; - vga_idx = cck_agc_rpt & 0x1F; + lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK); + vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK); if (priv->cck_agc_report_type == 0) lna_gain = lna_gain_table_0[lna_idx]; @@ -1788,6 +1784,7 @@ struct rtl8xxxu_fileops rtl8192eu_fops = { .set_tx_power = rtl8192e_set_tx_power, .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8xxxu_gen2_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, .set_crystal_cap = rtl8723a_set_crystal_cap, .cck_rssi = rtl8192e_cck_rssi, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c index 707ac48ecc83..5ed523db2d87 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c @@ -231,7 +231,7 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; switch (priv->chip_cut) { @@ -478,6 +478,7 @@ struct rtl8xxxu_fileops rtl8723au_fops = { .set_tx_power = rtl8xxxu_gen1_set_tx_power, .update_rate_mask = rtl8xxxu_update_rate_mask, .report_connect = rtl8xxxu_gen1_report_connect, + .report_rssi = rtl8xxxu_gen1_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v1, .set_crystal_cap = rtl8723a_set_crystal_cap, .cck_rssi = rtl8723a_cck_rssi, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index a0ec895b61a4..21613d60dc22 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -497,23 +497,12 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.41s\n", efuse->device_name); - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { - int i; - unsigned char *raw = priv->efuse_wifi.raw; - - dev_info(&priv->udev->dev, - "%s: dumping efuse (0x%02zx bytes):\n", - __func__, sizeof(struct rtl8723bu_efuse)); - for (i = 0; i < sizeof(struct rtl8723bu_efuse); i += 8) - dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); - } - return 0; } static int rtl8723bu_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; if (priv->enable_bluetooth) @@ -1691,8 +1680,8 @@ static s8 rtl8723b_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) s8 rx_pwr_all = 0x00; u8 vga_idx, lna_idx; - lna_idx = (cck_agc_rpt & 0xE0) >> 5; - vga_idx = cck_agc_rpt & 0x1F; + lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK); + vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK); switch (lna_idx) { case 6: @@ -1738,6 +1727,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .set_tx_power = rtl8723b_set_tx_power, .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8xxxu_gen2_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, .set_crystal_cap = rtl8723a_set_crystal_cap, .cck_rssi = rtl8723b_cck_rssi, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 3ed435401e57..35dc777c1fba 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -34,7 +34,7 @@ #define DRIVER_NAME "rtl8xxxu" -int rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE; +int rtl8xxxu_debug; static bool rtl8xxxu_ht40_2g; static bool rtl8xxxu_dma_aggregation; static int rtl8xxxu_dma_agg_timeout = -1; @@ -46,6 +46,7 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin"); MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin"); MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); @@ -1581,10 +1582,11 @@ static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv) cut = 'A' + priv->chip_cut; dev_info(dev, - "RTL%s rev %c (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n", - priv->chip_name, cut, priv->chip_vendor, priv->tx_paths, - priv->rx_paths, priv->ep_tx_count, priv->has_wifi, - priv->has_bluetooth, priv->has_gps, priv->hi_pa); + "RTL%s rev %c (%s) romver %d, %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n", + priv->chip_name, cut, priv->chip_vendor, priv->rom_rev, + priv->tx_paths, priv->rx_paths, priv->ep_tx_count, + priv->has_wifi, priv->has_bluetooth, priv->has_gps, + priv->hi_pa); dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr); } @@ -1813,6 +1815,16 @@ exit: return ret; } +static void rtl8xxxu_dump_efuse(struct rtl8xxxu_priv *priv) +{ + dev_info(&priv->udev->dev, + "Dumping efuse for RTL%s (0x%02x bytes):\n", + priv->chip_name, EFUSE_MAP_LEN); + + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, + priv->efuse_wifi.raw, EFUSE_MAP_LEN, true); +} + void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv) { u8 val8; @@ -1970,7 +1982,7 @@ fw_abort: return ret; } -int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name) +int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, const char *fw_name) { struct device *dev = &priv->udev->dev; const struct firmware *fw; @@ -2000,6 +2012,7 @@ int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name) switch (signature & 0xfff0) { case 0x92e0: case 0x92c0: + case 0x88e0: case 0x88c0: case 0x5300: case 0x2300: @@ -2071,10 +2084,20 @@ rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv) } } - if (priv->rtl_chip != RTL8723B && - priv->rtl_chip != RTL8192E && - priv->rtl_chip != RTL8188F) + switch (priv->rtl_chip) { + case RTL8188C: + case RTL8188R: + case RTL8191C: + case RTL8192C: + case RTL8723A: rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a); + break; + case RTL8188E: + rtl8xxxu_write16(priv, REG_MAX_AGGR_NUM, 0x0707); + break; + default: + break; + } return 0; } @@ -2373,11 +2396,16 @@ static int rtl8xxxu_llt_write(struct rtl8xxxu_priv *priv, u8 address, u8 data) int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv) { int ret; - int i; + int i, last_entry; u8 last_tx_page; last_tx_page = priv->fops->total_page_num; + if (priv->fops->last_llt_entry) + last_entry = priv->fops->last_llt_entry; + else + last_entry = 255; + for (i = 0; i < last_tx_page; i++) { ret = rtl8xxxu_llt_write(priv, i, i + 1); if (ret) @@ -2389,14 +2417,14 @@ int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv) goto exit; /* Mark remaining pages as a ring buffer */ - for (i = last_tx_page + 1; i < 0xff; i++) { + for (i = last_tx_page + 1; i < last_entry; i++) { ret = rtl8xxxu_llt_write(priv, i, (i + 1)); if (ret) goto exit; } /* Let last entry point to the start entry of ring buffer */ - ret = rtl8xxxu_llt_write(priv, 0xff, last_tx_page + 1); + ret = rtl8xxxu_llt_write(priv, last_entry, last_tx_page + 1); if (ret) goto exit; @@ -2704,8 +2732,8 @@ void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv, bool iqk_ok, #define MAX_TOLERANCE 5 -static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv, - int result[][8], int c1, int c2) +bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv, + int result[][8], int c1, int c2) { u32 i, j, diff, simubitmap, bound = 0; int candidate[2] = {-1, -1}; /* for path A and path B */ @@ -3898,7 +3926,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) goto exit; /* RFSW Control - clear bit 14 ?? */ - if (priv->rtl_chip != RTL8723B && priv->rtl_chip != RTL8192E) + if (priv->rtl_chip != RTL8723B && priv->rtl_chip != RTL8192E && + priv->rtl_chip != RTL8188E) rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003); val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW | @@ -3911,7 +3940,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32); /* 0x860[6:5]= 00 - why? - this sets antenna B */ - if (priv->rtl_chip != RTL8192E) + if (priv->rtl_chip != RTL8192E && priv->rtl_chip != RTL8188E) rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66f60210); if (!macpower) { @@ -3953,7 +3982,25 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) * Enable TX report and TX report timer for 8723bu/8188eu/... */ if (fops->has_tx_report) { + /* + * The RTL8188EU has two types of TX reports: + * rpt_sel=1: + * One report for one frame. We can use this for frames + * with IEEE80211_TX_CTL_REQ_TX_STATUS. + * rpt_sel=2: + * One report for many frames transmitted over a period + * of time. (This is what REG_TX_REPORT_TIME is for.) The + * report includes the number of frames transmitted + * successfully, and the number of unsuccessful + * transmissions. We use this for software rate control. + * + * Bit 0 of REG_TX_REPORT_CTRL is required for both types. + * Bit 1 (TX_REPORT_CTRL_TIMER_ENABLE) is required for + * type 2. + */ val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL); + if (priv->rtl_chip == RTL8188E) + val8 |= BIT(0); val8 |= TX_REPORT_CTRL_TIMER_ENABLE; rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8); /* Set MAX RPT MACID */ @@ -3979,6 +4026,15 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) } else if (priv->rtl_chip == RTL8188F) { rtl8xxxu_write32(priv, REG_HISR0, 0xffffffff); rtl8xxxu_write32(priv, REG_HISR1, 0xffffffff); + } else if (priv->rtl_chip == RTL8188E) { + rtl8xxxu_write32(priv, REG_HISR0, 0xffffffff); + val32 = IMR0_PSTIMEOUT | IMR0_TBDER | IMR0_CPWM | IMR0_CPWM2; + rtl8xxxu_write32(priv, REG_HIMR0, val32); + val32 = IMR1_TXERR | IMR1_RXERR | IMR1_TXFOVW | IMR1_RXFOVW; + rtl8xxxu_write32(priv, REG_HIMR1, val32); + val8 = rtl8xxxu_read8(priv, REG_USB_SPECIAL_OPTION); + val8 |= USB_SPEC_INT_BULK_SELECT; + rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, val8); } else { /* * Enable all interrupts - not obvious USB needs to do this @@ -4084,7 +4140,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (fops->init_aggregation) fops->init_aggregation(priv); - if (priv->rtl_chip == RTL8188F) { + if (priv->rtl_chip == RTL8188F || priv->rtl_chip == RTL8188E) { rtl8xxxu_write16(priv, REG_PKT_VO_VI_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ rtl8xxxu_write16(priv, REG_PKT_BE_BK_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ } @@ -4118,7 +4174,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* Disable BAR - not sure if this has any effect on USB */ rtl8xxxu_write32(priv, REG_BAR_MODE_CTRL, 0x0201ffff); - if (priv->rtl_chip != RTL8188F) + if (priv->rtl_chip != RTL8188F && priv->rtl_chip != RTL8188E) rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0); if (fops->init_statistics) @@ -4136,9 +4192,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) * Reset USB mode switch setting */ rtl8xxxu_write8(priv, REG_ACLK_MON, 0x00); - } else if (priv->rtl_chip == RTL8188F) { + } else if (priv->rtl_chip == RTL8188F || priv->rtl_chip == RTL8188E) { /* - * Init GPIO settings for 8188f + * Init GPIO settings for 8188f, 8188e */ val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG); val8 &= ~GPIO_MUXCFG_IO_SEL_ENBT; @@ -4184,7 +4240,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) val32 |= FPGA_RF_MODE_CCK; rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); } - } else if (priv->rtl_chip == RTL8192E) { + } else if (priv->rtl_chip == RTL8192E || priv->rtl_chip == RTL8188E) { rtl8xxxu_write8(priv, REG_USB_HRPWM, 0x00); } @@ -4208,10 +4264,12 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) * should be equal or CCK RSSI report may be incorrect */ val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2); - priv->cck_agc_report_type = val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR; + priv->cck_agc_report_type = + u32_get_bits(val32, FPGA0_HSSI_PARM2_CCK_HIGH_PWR); val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_HSSI_PARM2); - if (priv->cck_agc_report_type != (bool)(val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR)) { + if (priv->cck_agc_report_type != + u32_get_bits(val32, FPGA0_HSSI_PARM2_CCK_HIGH_PWR)) { if (priv->cck_agc_report_type) val32 |= FPGA0_HSSI_PARM2_CCK_HIGH_PWR; else @@ -4235,6 +4293,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) priv->cfo_tracking.crystal_cap = priv->default_crystal_cap; } + if (priv->rtl_chip == RTL8188E) + rtl8188e_ra_info_init_all(&priv->ra_info); + exit: return ret; } @@ -4401,6 +4462,37 @@ void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt)); } +void rtl8xxxu_gen1_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi) +{ + struct h2c_cmd h2c; + const int h2c_size = 4; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + + h2c.rssi_report.cmd = H2C_SET_RSSI; + h2c.rssi_report.macid = macid; + h2c.rssi_report.rssi = rssi; + + rtl8xxxu_gen1_h2c_cmd(priv, &h2c, h2c_size); +} + +void rtl8xxxu_gen2_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi) +{ + struct h2c_cmd h2c; + int h2c_size = sizeof(h2c.rssi_report); + + if (priv->rtl_chip == RTL8723B) + h2c_size = 4; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + + h2c.rssi_report.cmd = H2C_8723B_RSSI_SETTING; + h2c.rssi_report.macid = macid; + h2c.rssi_report.rssi = rssi; + + rtl8xxxu_gen2_h2c_cmd(priv, &h2c, h2c_size); +} + void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv) { u8 agg_ctrl, usb_spec, page_thresh, timeout; @@ -4598,8 +4690,8 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time) } } -static void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt, - u8 rate, u8 sgi, u8 bw) +void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt, + u8 rate, u8 sgi, u8 bw) { u8 mcs, nss; @@ -5069,6 +5161,98 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, } } +/* + * Fill in v3 (gen1) specific TX descriptor bits. + * This format is a hybrid between the v1 and v2 formats, only seen + * on 8188eu devices so far. + */ +void +rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + struct ieee80211_tx_info *tx_info, + struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, + bool short_preamble, bool ampdu_enable, u32 rts_rate) +{ + struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + struct rtl8xxxu_ra_info *ra = &priv->ra_info; + 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; + + if (rate_flags & IEEE80211_TX_RC_MCS && + !ieee80211_is_mgmt(hdr->frame_control)) + rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; + else + rate = tx_rate->hw_value; + + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + if (ieee80211_is_data(hdr->frame_control)) { + rate = ra->decision_rate; + tx_desc->txdw5 = cpu_to_le32(rate); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_USE_DRIVER_RATE); + tx_desc->txdw4 |= le32_encode_bits(ra->pt_stage, TXDESC32_PT_STAGE_MASK); + /* Data/RTS rate FB limit */ + tx_desc->txdw5 |= cpu_to_le32(0x0001ff00); + } + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) + dev_info(dev, "%s: TX rate: %d, pkt size %d\n", + __func__, rate, le16_to_cpu(tx_desc->pkt_size)); + + tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC32_SEQ_SHIFT); + + if (ampdu_enable && test_bit(tid, priv->tid_tx_operational)) + tx_desc->txdw2 |= cpu_to_le32(TXDESC40_AGG_ENABLE); + else + tx_desc->txdw2 |= cpu_to_le32(TXDESC40_AGG_BREAK); + + if (ieee80211_is_mgmt(hdr->frame_control)) { + tx_desc->txdw5 = cpu_to_le32(rate); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_USE_DRIVER_RATE); + tx_desc->txdw5 |= cpu_to_le32(6 << TXDESC32_RETRY_LIMIT_SHIFT); + tx_desc->txdw5 |= cpu_to_le32(TXDESC32_RETRY_LIMIT_ENABLE); + } + + if (ieee80211_is_data_qos(hdr->frame_control)) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_QOS); + + if (conf_is_ht40(&hw->conf)) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC_DATA_BW); + + if (conf_is_ht40_minus(&hw->conf)) + tx_desc->txdw4 |= cpu_to_le32(TXDESC_PRIME_CH_OFF_UPPER); + else + tx_desc->txdw4 |= cpu_to_le32(TXDESC_PRIME_CH_OFF_LOWER); + } + } + + if (short_preamble) + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_SHORT_PREAMBLE); + + if (sgi && ra->rate_sgi) + tx_desc->txdw5 |= cpu_to_le32(TXDESC32_SHORT_GI); + + /* + * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled + */ + tx_desc->txdw4 |= cpu_to_le32(rts_rate << TXDESC32_RTS_RATE_SHIFT); + if (ampdu_enable || (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS)) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_RTS_CTS_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); + } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_CTS_SELF_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); + } + + tx_desc->txdw2 |= cpu_to_le32(TXDESC_ANTENNA_SELECT_A | + TXDESC_ANTENNA_SELECT_B); + tx_desc->txdw7 |= cpu_to_le32(TXDESC_ANTENNA_SELECT_C); +} + static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -5274,7 +5458,7 @@ static void rtl8xxxu_queue_rx_urb(struct rtl8xxxu_priv *priv, pending = priv->rx_urb_pending_count; } else { skb = (struct sk_buff *)rx_urb->urb.context; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); usb_free_urb(&rx_urb->urb); } @@ -5550,9 +5734,6 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) btcoex = &priv->bt_coex; rarpt = &priv->ra_report; - if (priv->rf_paths > 1) - goto out; - while (!skb_queue_empty(&priv->c2hcmd_queue)) { skb = skb_dequeue(&priv->c2hcmd_queue); @@ -5585,10 +5766,9 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) default: break; } - } -out: - dev_kfree_skb(skb); + dev_kfree_skb(skb); + } } static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, @@ -5640,6 +5820,44 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, schedule_work(&priv->c2hcmd_work); } +static void rtl8188e_c2hcmd_callback(struct work_struct *work) +{ + struct rtl8xxxu_priv *priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work); + struct device *dev = &priv->udev->dev; + struct sk_buff *skb = NULL; + struct rtl8xxxu_rxdesc16 *rx_desc; + + while (!skb_queue_empty(&priv->c2hcmd_queue)) { + skb = skb_dequeue(&priv->c2hcmd_queue); + + rx_desc = (struct rtl8xxxu_rxdesc16 *)(skb->data - sizeof(struct rtl8xxxu_rxdesc16)); + + switch (rx_desc->rpt_sel) { + case 1: + dev_dbg(dev, "C2H TX report type 1\n"); + + break; + case 2: + dev_dbg(dev, "C2H TX report type 2\n"); + + rtl8188e_handle_ra_tx_report2(priv, skb); + + break; + case 3: + dev_dbg(dev, "C2H USB interrupt report\n"); + + break; + default: + dev_warn(dev, "%s: rpt_sel should not be %d\n", + __func__, rx_desc->rpt_sel); + + break; + } + + dev_kfree_skb(skb); + } +} + int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { struct ieee80211_hw *hw = priv->hw; @@ -5695,38 +5913,45 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc16)); - phy_stats = (struct rtl8723au_phy_stats *)skb->data; + if (rx_desc->rpt_sel) { + skb_queue_tail(&priv->c2hcmd_queue, skb); + schedule_work(&priv->c2hcmd_work); + } else { + phy_stats = (struct rtl8723au_phy_stats *)skb->data; - skb_pull(skb, drvinfo_sz + desc_shift); + skb_pull(skb, drvinfo_sz + desc_shift); - skb_trim(skb, pkt_len); + skb_trim(skb, pkt_len); - if (rx_desc->phy_stats) - rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, - rx_desc->rxmcs, (struct ieee80211_hdr *)skb->data, - rx_desc->crc32 || rx_desc->icverr); + if (rx_desc->phy_stats) + rtl8xxxu_rx_parse_phystats( + priv, rx_status, phy_stats, + rx_desc->rxmcs, + (struct ieee80211_hdr *)skb->data, + rx_desc->crc32 || rx_desc->icverr); - rx_status->mactime = rx_desc->tsfl; - rx_status->flag |= RX_FLAG_MACTIME_START; + rx_status->mactime = rx_desc->tsfl; + rx_status->flag |= RX_FLAG_MACTIME_START; - if (!rx_desc->swdec) - rx_status->flag |= RX_FLAG_DECRYPTED; - if (rx_desc->crc32) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rx_desc->bw) - rx_status->bw = RATE_INFO_BW_40; + if (!rx_desc->swdec) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (rx_desc->crc32) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_desc->bw) + rx_status->bw = RATE_INFO_BW_40; - if (rx_desc->rxht) { - rx_status->encoding = RX_ENC_HT; - rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; - } else { - rx_status->rate_idx = rx_desc->rxmcs; - } + if (rx_desc->rxht) { + rx_status->encoding = RX_ENC_HT; + rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; + } else { + rx_status->rate_idx = rx_desc->rxmcs; + } - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->band = hw->conf.chandef.chan->band; + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; - ieee80211_rx_irqsafe(hw, skb); + ieee80211_rx_irqsafe(hw, skb); + } skb = next_skb; if (skb) @@ -5956,7 +6181,6 @@ static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) { struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; - u16 val16; int ret = 0, channel; bool ht40; @@ -5966,14 +6190,6 @@ static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) __func__, hw->conf.chandef.chan->hw_value, changed, hw->conf.chandef.width); - if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - val16 = ((hw->conf.long_frame_max_tx_count << - RETRY_LIMIT_LONG_SHIFT) & RETRY_LIMIT_LONG_MASK) | - ((hw->conf.short_frame_max_tx_count << - RETRY_LIMIT_SHORT_SHIFT) & RETRY_LIMIT_SHORT_MASK); - rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16); - } - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { switch (hw->conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: @@ -6504,6 +6720,9 @@ static void rtl8xxxu_watchdog_callback(struct work_struct *work) signal = ieee80211_ave_rssi(vif); + priv->fops->report_rssi(priv, 0, + rtl8xxxu_signal_to_snr(signal)); + if (priv->fops->set_crystal_cap) rtl8xxxu_track_cfo(priv); @@ -6587,7 +6806,10 @@ exit: rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff); rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff); - rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e); + if (priv->rtl_chip == RTL8188E) + rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6955341e); + else + rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e); return ret; @@ -6754,6 +6976,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, case 0x817f: case 0x818b: case 0xf179: + case 0x8179: untested = 0; break; } @@ -6809,7 +7032,6 @@ static int rtl8xxxu_probe(struct usb_interface *interface, spin_lock_init(&priv->rx_urb_lock); INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback); - INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback); skb_queue_head_init(&priv->c2hcmd_queue); usb_set_intfdata(interface, hw); @@ -6827,6 +7049,11 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->wiphy->available_antennas_tx = BIT(priv->tx_paths) - 1; hw->wiphy->available_antennas_rx = BIT(priv->rx_paths) - 1; + if (priv->rtl_chip == RTL8188E) + INIT_WORK(&priv->c2hcmd_work, rtl8188e_c2hcmd_callback); + else + INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback); + ret = rtl8xxxu_read_efuse(priv); if (ret) { dev_err(&udev->dev, "Fatal - failed to read EFuse\n"); @@ -6839,6 +7066,9 @@ static int rtl8xxxu_probe(struct usb_interface *interface, goto err_set_intfdata; } + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) + rtl8xxxu_dump_efuse(priv); + rtl8xxxu_print_chipinfo(priv); ret = priv->fops->load_firmware(priv); @@ -6887,8 +7117,10 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->extra_tx_headroom = priv->fops->tx_desc_size; ieee80211_hw_set(hw, SIGNAL_DBM); + /* - * The firmware handles rate control + * The firmware handles rate control, except for RTL8188EU, + * where we handle the rate control in the driver. */ ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); @@ -6973,6 +7205,50 @@ static const struct usb_device_id dev_table[] = { /* RTL8188FU */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0xf179, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8188fu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8179, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Tested by Hans de Goede - rtl8188etv */ +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x0179, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Sitecom rtl8188eus */ +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0076, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* D-Link USB-GO-N150 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3311, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* D-Link DWA-125 REV D1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330f, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* D-Link DWA-123 REV D1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3310, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* D-Link DWA-121 rev B1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Abocom - Abocom */ +{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8179, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Elecom WDC-150SU2M */ +{USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x4008, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* TP-Link TL-WN722N v2 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x010c, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* TP-Link TL-WN727N v5.21 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0111, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* MERCUSYS MW150US v2 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0102, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* ASUS USB-N10 Nano B1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x18f0, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, + /* Edimax EW-7811Un V2 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xb811, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Rosewill USB-N150 Nano */ +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0xffef, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, #ifdef CONFIG_RTL8XXXU_UNTESTED /* Still supported by rtlwifi */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 3e79efdfb4c2..5818b2378bab 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -371,6 +371,11 @@ #define PBP_PAGE_SIZE_512 0x3 #define PBP_PAGE_SIZE_1024 0x4 +/* 8188eu IOL magic */ +#define REG_PKT_BUF_ACCESS_CTRL 0x0106 +#define PKT_BUF_ACCESS_CTRL_TX 0x69 +#define PKT_BUF_ACCESS_CTRL_RX 0xa5 + #define REG_TRXDMA_CTRL 0x010c #define TRXDMA_CTRL_RXDMA_AGG_EN BIT(2) #define TRXDMA_CTRL_VOQ_SHIFT 4 @@ -407,6 +412,8 @@ #define REG_MBIST_START 0x0174 #define REG_MBIST_DONE 0x0178 #define REG_MBIST_FAIL 0x017c +/* 8188EU */ +#define REG_32K_CTRL 0x0194 #define REG_C2HEVT_MSG_NORMAL 0x01a0 /* 8192EU/8723BU/8812 */ #define REG_C2HEVT_CMD_ID_8723B 0x01ae @@ -942,6 +949,16 @@ #define REG_FPGA1_RF_MODE 0x0900 #define REG_FPGA1_TX_INFO 0x090c +#define FPGA1_TX_ANT_MASK 0x0000000f +#define FPGA1_TX_ANT_L_MASK 0x000000f0 +#define FPGA1_TX_ANT_NON_HT_MASK 0x00000f00 +#define FPGA1_TX_ANT_HT1_MASK 0x0000f000 +#define FPGA1_TX_ANT_HT2_MASK 0x000f0000 +#define FPGA1_TX_ANT_HT_S1_MASK 0x00f00000 +#define FPGA1_TX_ANT_NON_HT_S1_MASK 0x0f000000 +#define FPGA1_TX_OFDM_TXSC_MASK 0x30000000 + +#define REG_ANT_MAPPING1 0x0914 #define REG_DPDT_CTRL 0x092c /* 8723BU */ #define REG_RFE_CTRL_ANTA_SRC 0x0930 /* 8723BU */ #define REG_RFE_PATH_SELECT 0x0940 /* 8723BU */ @@ -954,9 +971,25 @@ #define REG_CCK0_AFE_SETTING 0x0a04 #define CCK0_AFE_RX_MASK 0x0f000000 -#define CCK0_AFE_RX_ANT_AB BIT(24) +#define CCK0_AFE_TX_MASK 0xf0000000 #define CCK0_AFE_RX_ANT_A 0 -#define CCK0_AFE_RX_ANT_B (BIT(24) | BIT(26)) +#define CCK0_AFE_RX_ANT_B BIT(26) +#define CCK0_AFE_RX_ANT_C BIT(27) +#define CCK0_AFE_RX_ANT_D (BIT(26) | BIT(27)) +#define CCK0_AFE_RX_ANT_OPTION_A 0 +#define CCK0_AFE_RX_ANT_OPTION_B BIT(24) +#define CCK0_AFE_RX_ANT_OPTION_C BIT(25) +#define CCK0_AFE_RX_ANT_OPTION_D (BIT(24) | BIT(25)) +#define CCK0_AFE_TX_ANT_A BIT(31) +#define CCK0_AFE_TX_ANT_B BIT(30) + +#define REG_CCK_ANTDIV_PARA2 0x0a04 +#define REG_BB_POWER_SAVE4 0x0a74 + +/* 8188eu */ +#define REG_LNA_SWITCH 0x0b2c +#define LNA_SWITCH_DISABLE_CSCG BIT(22) +#define LNA_SWITCH_OUTPUT_CG BIT(31) #define REG_CCK_PD_THRESH 0x0a0a #define CCK_PD_TYPE1_LV0_TH 0x40 @@ -1020,6 +1053,9 @@ #define REG_OFDM0_RX_IQ_EXT_ANTA 0x0ca0 +/* 8188eu */ +#define REG_ANTDIV_PARA1 0x0ca4 + /* 8723bu */ #define REG_OFDM0_TX_PSDO_NOISE_WEIGHT 0x0ce4 diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c index 58c2ab3d44be..de61c9c0ddec 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c @@ -68,8 +68,10 @@ static void _rtl88ee_return_beacon_queue_skb(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct sk_buff_head free_list; unsigned long flags; + skb_queue_head_init(&free_list); spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); while (skb_queue_len(&ring->queue)) { struct rtl_tx_desc *entry = &ring->desc[ring->idx]; @@ -79,10 +81,12 @@ static void _rtl88ee_return_beacon_queue_skb(struct ieee80211_hw *hw) rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), skb->len, DMA_TO_DEVICE); - kfree_skb(skb); + __skb_queue_tail(&free_list, skb); ring->idx = (ring->idx + 1) % ring->entries; } spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + __skb_queue_purge(&free_list); } static void _rtl88ee_disable_bcn_sub_func(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_bt_coexist.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_bt_coexist.h index 0455a3712f3e..12cdecdafc32 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_bt_coexist.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_bt_coexist.h @@ -116,7 +116,7 @@ void rtl8723e_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw); long rtl8723e_dm_bt_get_rx_ss(struct ieee80211_hw *hw); void rtl8723e_dm_bt_balance(struct ieee80211_hw *hw, bool balance_on, u8 ms0, u8 ms1); -void rtl8723e_dm_bt_agc_table(struct ieee80211_hw *hw, u8 tyep); +void rtl8723e_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type); void rtl8723e_dm_bt_bb_back_off_level(struct ieee80211_hw *hw, u8 type); u8 rtl8723e_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw, u8 level_num, u8 rssi_thresh, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 189cc6437600..0ba3bbed6ed3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -30,8 +30,10 @@ static void _rtl8723be_return_beacon_queue_skb(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct sk_buff_head free_list; unsigned long flags; + skb_queue_head_init(&free_list); spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); while (skb_queue_len(&ring->queue)) { struct rtl_tx_desc *entry = &ring->desc[ring->idx]; @@ -41,10 +43,12 @@ static void _rtl8723be_return_beacon_queue_skb(struct ieee80211_hw *hw) rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), skb->len, DMA_TO_DEVICE); - kfree_skb(skb); + __skb_queue_tail(&free_list, skb); ring->idx = (ring->idx + 1) % ring->entries; } spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + __skb_queue_purge(&free_list); } static void _rtl8723be_set_bcn_ctrl_reg(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 7e0f62d59fe1..a7e3250957dc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -26,8 +26,10 @@ static void _rtl8821ae_return_beacon_queue_skb(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct sk_buff_head free_list; unsigned long flags; + skb_queue_head_init(&free_list); spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); while (skb_queue_len(&ring->queue)) { struct rtl_tx_desc *entry = &ring->desc[ring->idx]; @@ -37,10 +39,12 @@ static void _rtl8821ae_return_beacon_queue_skb(struct ieee80211_hw *hw) rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), skb->len, DMA_TO_DEVICE); - kfree_skb(skb); + __skb_queue_tail(&free_list, skb); ring->idx = (ring->idx + 1) % ring->entries; } spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + __skb_queue_purge(&free_list); } static void _rtl8821ae_set_bcn_ctrl_reg(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index a29321e2fa72..5323ead30db0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -1598,18 +1598,6 @@ static bool _rtl8812ae_get_integer_from_string(const char *str, u8 *pint) return true; } -static bool _rtl8812ae_eq_n_byte(const char *str1, const char *str2, u32 num) -{ - if (num == 0) - return false; - while (num > 0) { - num--; - if (str1[num] != str2[num]) - return false; - } - return true; -} - static s8 _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw, u8 band, u8 channel) { @@ -1659,42 +1647,42 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, power_limit = power_limit > MAX_POWER_INDEX ? MAX_POWER_INDEX : power_limit; - if (_rtl8812ae_eq_n_byte(pregulation, "FCC", 3)) + if (strcmp(pregulation, "FCC") == 0) regulation = 0; - else if (_rtl8812ae_eq_n_byte(pregulation, "MKK", 3)) + else if (strcmp(pregulation, "MKK") == 0) regulation = 1; - else if (_rtl8812ae_eq_n_byte(pregulation, "ETSI", 4)) + else if (strcmp(pregulation, "ETSI") == 0) regulation = 2; - else if (_rtl8812ae_eq_n_byte(pregulation, "WW13", 4)) + else if (strcmp(pregulation, "WW13") == 0) regulation = 3; - if (_rtl8812ae_eq_n_byte(prate_section, "CCK", 3)) + if (strcmp(prate_section, "CCK") == 0) rate_section = 0; - else if (_rtl8812ae_eq_n_byte(prate_section, "OFDM", 4)) + else if (strcmp(prate_section, "OFDM") == 0) rate_section = 1; - else if (_rtl8812ae_eq_n_byte(prate_section, "HT", 2) && - _rtl8812ae_eq_n_byte(prf_path, "1T", 2)) + else if (strcmp(prate_section, "HT") == 0 && + strcmp(prf_path, "1T") == 0) rate_section = 2; - else if (_rtl8812ae_eq_n_byte(prate_section, "HT", 2) && - _rtl8812ae_eq_n_byte(prf_path, "2T", 2)) + else if (strcmp(prate_section, "HT") == 0 && + strcmp(prf_path, "2T") == 0) rate_section = 3; - else if (_rtl8812ae_eq_n_byte(prate_section, "VHT", 3) && - _rtl8812ae_eq_n_byte(prf_path, "1T", 2)) + else if (strcmp(prate_section, "VHT") == 0 && + strcmp(prf_path, "1T") == 0) rate_section = 4; - else if (_rtl8812ae_eq_n_byte(prate_section, "VHT", 3) && - _rtl8812ae_eq_n_byte(prf_path, "2T", 2)) + else if (strcmp(prate_section, "VHT") == 0 && + strcmp(prf_path, "2T") == 0) rate_section = 5; - if (_rtl8812ae_eq_n_byte(pbandwidth, "20M", 3)) + if (strcmp(pbandwidth, "20M") == 0) bandwidth = 0; - else if (_rtl8812ae_eq_n_byte(pbandwidth, "40M", 3)) + else if (strcmp(pbandwidth, "40M") == 0) bandwidth = 1; - else if (_rtl8812ae_eq_n_byte(pbandwidth, "80M", 3)) + else if (strcmp(pbandwidth, "80M") == 0) bandwidth = 2; - else if (_rtl8812ae_eq_n_byte(pbandwidth, "160M", 4)) + else if (strcmp(pbandwidth, "160M") == 0) bandwidth = 3; - if (_rtl8812ae_eq_n_byte(pband, "2.4G", 4)) { + if (strcmp(pband, "2.4G") == 0) { ret = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw, BAND_ON_2_4G, channel); @@ -1718,7 +1706,7 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, regulation, bandwidth, rate_section, channel_index, rtlphy->txpwr_limit_2_4g[regulation][bandwidth] [rate_section][channel_index][RF90_PATH_A]); - } else if (_rtl8812ae_eq_n_byte(pband, "5G", 2)) { + } else if (strcmp(pband, "5G") == 0) { ret = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw, BAND_ON_5G, channel); diff --git a/drivers/net/wireless/realtek/rtw88/bf.c b/drivers/net/wireless/realtek/rtw88/bf.c index 038a30b170ef..c827c4a2814b 100644 --- a/drivers/net/wireless/realtek/rtw88/bf.c +++ b/drivers/net/wireless/realtek/rtw88/bf.c @@ -49,19 +49,23 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, sta = ieee80211_find_sta(vif, bssid); if (!sta) { + rcu_read_unlock(); + rtw_warn(rtwdev, "failed to find station entry for bss %pM\n", bssid); - goto out_unlock; + return; } ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap; vht_cap = &sta->deflink.vht_cap; + rcu_read_unlock(); + if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) { rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n"); - goto out_unlock; + return; } ether_addr_copy(bfee->mac_addr, bssid); @@ -75,7 +79,7 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) { rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n"); - goto out_unlock; + return; } sound_dim = vht_cap->cap & @@ -98,9 +102,6 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true); } - -out_unlock: - rcu_read_unlock(); } void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 776a9a9884b5..3b92ac611d3f 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -737,7 +737,7 @@ static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev, br_data.rtwdev = rtwdev; br_data.vif = vif; br_data.mask = mask; - rtw_iterate_stas_atomic(rtwdev, rtw_ra_mask_info_update_iter, &br_data); + rtw_iterate_stas(rtwdev, rtw_ra_mask_info_update_iter, &br_data); } static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, @@ -746,7 +746,9 @@ static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; + mutex_lock(&rtwdev->mutex); rtw_ra_mask_info_update(rtwdev, vif, mask); + mutex_unlock(&rtwdev->mutex); return 0; } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 888427cf3bdf..b2e78737bd5d 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -241,8 +241,10 @@ static void rtw_watch_dog_work(struct work_struct *work) rtw_phy_dynamic_mechanism(rtwdev); data.rtwdev = rtwdev; - /* use atomic version to avoid taking local->iflist_mtx mutex */ - rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); + /* rtw_iterate_vifs internally uses an atomic iterator which is needed + * to avoid taking local->iflist_mtx mutex + */ + rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index f21c73310fdb..d48ae25823ff 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -120,6 +120,70 @@ static const u32 cxtbl[] = { 0xfafadafa /* 19 */ }; +static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { + /* firmware version must be in decreasing order for each chip */ + {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), + .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .info_buf = 1800, .max_role_num = 6, + }, + {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), + .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, + .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, + .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, + .info_buf = 1024, .max_role_num = 5, + }, + + /* keep it to be the last as default entry */ + {0, RTW89_FW_VER_CODE(0, 0, 0, 0), + .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, + .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, + .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, + .info_buf = 1024, .max_role_num = 5, + }, +}; + +#define RTW89_DEFAULT_BTC_VER_IDX (ARRAY_SIZE(rtw89_btc_ver_defs) - 1) + struct rtw89_btc_btf_tlv { u8 type; u8 len; @@ -127,16 +191,20 @@ struct rtw89_btc_btf_tlv { } __packed; enum btc_btf_set_report_en { - RPT_EN_TDMA = BIT(0), - RPT_EN_CYCLE = BIT(1), - RPT_EN_MREG = BIT(2), - RPT_EN_BT_VER_INFO = BIT(3), - RPT_EN_BT_SCAN_INFO = BIT(4), - RPT_EN_BT_AFH_MAP = BIT(5), - RPT_EN_BT_DEVICE_INFO = BIT(6), - RPT_EN_WL_ALL = GENMASK(2, 0), - RPT_EN_BT_ALL = GENMASK(6, 3), - RPT_EN_ALL = GENMASK(6, 0), + RPT_EN_TDMA, + RPT_EN_CYCLE, + RPT_EN_MREG, + RPT_EN_BT_VER_INFO, + RPT_EN_BT_SCAN_INFO, + RPT_EN_BT_DEVICE_INFO, + RPT_EN_BT_AFH_MAP, + RPT_EN_BT_AFH_MAP_LE, + RPT_EN_FW_STEP_INFO, + RPT_EN_TEST, + RPT_EN_WL_ALL, + RPT_EN_BT_ALL, + RPT_EN_ALL, + RPT_EN_MONITER, }; #define BTF_SET_REPORT_VER 1 @@ -786,17 +854,18 @@ static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt) static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; struct rtw89_btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc; struct rtw89_btc_fbtc_btver *pver = NULL; struct rtw89_btc_fbtc_btscan *pscan = NULL; - struct rtw89_btc_fbtc_btafh *pafh = NULL; + struct rtw89_btc_fbtc_btafh *pafh_v1 = NULL; + struct rtw89_btc_fbtc_btafh_v2 *pafh_v2 = NULL; struct rtw89_btc_fbtc_btdevinfo *pdev = NULL; pver = (struct rtw89_btc_fbtc_btver *)pfinfo; pscan = (struct rtw89_btc_fbtc_btscan *)pfinfo; - pafh = (struct rtw89_btc_fbtc_btafh *)pfinfo; pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo; rtw89_debug(rtwdev, RTW89_DBG_BTC, @@ -813,9 +882,23 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo) memcpy(bt->scan_info, pscan->scan, BTC_SCAN_MAX1); break; case BTC_RPT_TYPE_BT_AFH: - memcpy(&bt_linfo->afh_map[0], pafh->afh_l, 4); - memcpy(&bt_linfo->afh_map[4], pafh->afh_m, 4); - memcpy(&bt_linfo->afh_map[8], pafh->afh_h, 2); + if (ver->fcxbtafh == 2) { + pafh_v2 = (struct rtw89_btc_fbtc_btafh_v2 *)pfinfo; + if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LEGACY) { + memcpy(&bt_linfo->afh_map[0], pafh_v2->afh_l, 4); + memcpy(&bt_linfo->afh_map[4], pafh_v2->afh_m, 4); + memcpy(&bt_linfo->afh_map[8], pafh_v2->afh_h, 2); + } + if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LE) { + memcpy(&bt_linfo->afh_map_le[0], pafh_v2->afh_le_a, 4); + memcpy(&bt_linfo->afh_map_le[4], pafh_v2->afh_le_b, 1); + } + } else if (ver->fcxbtafh == 1) { + pafh_v1 = (struct rtw89_btc_fbtc_btafh *)pfinfo; + memcpy(&bt_linfo->afh_map[0], pafh_v1->afh_l, 4); + memcpy(&bt_linfo->afh_map[4], pafh_v1->afh_m, 4); + memcpy(&bt_linfo->afh_map[8], pafh_v1->afh_h, 2); + } break; case BTC_RPT_TYPE_BT_DEVICE: a2dp->device_name = le32_to_cpu(pdev->dev_name); @@ -827,76 +910,6 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo) } } -struct rtw89_btc_fbtc_cysta_cpu { - u8 fver; - u8 rsvd; - u16 cycles; - u16 cycles_a2dp[CXT_FLCTRL_MAX]; - u16 a2dpept; - u16 a2dpeptto; - u16 tavg_cycle[CXT_MAX]; - u16 tmax_cycle[CXT_MAX]; - u16 tmaxdiff_cycle[CXT_MAX]; - u16 tavg_a2dp[CXT_FLCTRL_MAX]; - u16 tmax_a2dp[CXT_FLCTRL_MAX]; - u16 tavg_a2dpept; - u16 tmax_a2dpept; - u16 tavg_lk; - u16 tmax_lk; - u32 slot_cnt[CXST_MAX]; - u32 bcn_cnt[CXBCN_MAX]; - u32 leakrx_cnt; - u32 collision_cnt; - u32 skip_cnt; - u32 exception; - u32 except_cnt; - u16 tslot_cycle[BTC_CYCLE_SLOT_MAX]; -}; - -static void rtw89_btc_fbtc_cysta_to_cpu(const struct rtw89_btc_fbtc_cysta *src, - struct rtw89_btc_fbtc_cysta_cpu *dst) -{ - static_assert(sizeof(*src) == sizeof(*dst)); - -#define __CPY_U8(_x) ({dst->_x = src->_x; }) -#define __CPY_LE16(_x) ({dst->_x = le16_to_cpu(src->_x); }) -#define __CPY_LE16S(_x) ({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \ - dst->_x[_i] = le16_to_cpu(src->_x[_i]); }) -#define __CPY_LE32(_x) ({dst->_x = le32_to_cpu(src->_x); }) -#define __CPY_LE32S(_x) ({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \ - dst->_x[_i] = le32_to_cpu(src->_x[_i]); }) - - __CPY_U8(fver); - __CPY_U8(rsvd); - __CPY_LE16(cycles); - __CPY_LE16S(cycles_a2dp); - __CPY_LE16(a2dpept); - __CPY_LE16(a2dpeptto); - __CPY_LE16S(tavg_cycle); - __CPY_LE16S(tmax_cycle); - __CPY_LE16S(tmaxdiff_cycle); - __CPY_LE16S(tavg_a2dp); - __CPY_LE16S(tmax_a2dp); - __CPY_LE16(tavg_a2dpept); - __CPY_LE16(tmax_a2dpept); - __CPY_LE16(tavg_lk); - __CPY_LE16(tmax_lk); - __CPY_LE32S(slot_cnt); - __CPY_LE32S(bcn_cnt); - __CPY_LE32(leakrx_cnt); - __CPY_LE32(collision_cnt); - __CPY_LE32(skip_cnt); - __CPY_LE32(exception); - __CPY_LE32(except_cnt); - __CPY_LE16S(tslot_cycle); - -#undef __CPY_U8 -#undef __CPY_LE16 -#undef __CPY_LE16S -#undef __CPY_LE32 -#undef __CPY_LE32S -} - #define BTC_LEAK_AP_TH 10 #define BTC_CYSTA_CHK_PERIOD 100 @@ -910,19 +923,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, struct rtw89_btc_btf_fwinfo *pfwinfo, u8 *prptbuf, u32 index) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_bt_info *bt = &btc->cx.bt; - struct rtw89_btc_fbtc_rpt_ctrl *prpt; - struct rtw89_btc_fbtc_rpt_ctrl_v1 *prpt_v1; - struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL; - struct rtw89_btc_fbtc_cysta_v1 *pcysta_v1 = NULL; - struct rtw89_btc_fbtc_cysta_cpu pcysta[1]; + union rtw89_btc_fbtc_rpt_ctrl_ver_info *prpt = NULL; + union rtw89_btc_fbtc_cysta_info *pcysta = NULL; struct rtw89_btc_prpt *btc_prpt = NULL; - struct rtw89_btc_fbtc_slot *rtp_slot = NULL; void *rpt_content = NULL, *pfinfo = NULL; u8 rpt_type = 0; u16 wl_slot_set = 0, wl_slot_real = 0; @@ -951,137 +960,141 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, switch (rpt_type) { case BTC_RPT_TYPE_CTRL: pcinfo = &pfwinfo->rpt_ctrl.cinfo; - if (chip->chip_id == RTL8852A) { - pfinfo = &pfwinfo->rpt_ctrl.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo); + prpt = &pfwinfo->rpt_ctrl.finfo; + if (ver->fcxbtcrpt == 1) { + pfinfo = &pfwinfo->rpt_ctrl.finfo.v1; + pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v1); + } else if (ver->fcxbtcrpt == 4) { + pfinfo = &pfwinfo->rpt_ctrl.finfo.v4; + pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v4); + } else if (ver->fcxbtcrpt == 5) { + pfinfo = &pfwinfo->rpt_ctrl.finfo.v5; + pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v5); } else { - pfinfo = &pfwinfo->rpt_ctrl.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo_v1); + goto err; } - pcinfo->req_fver = chip->fcxbtcrpt_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxbtcrpt; break; case BTC_RPT_TYPE_TDMA: pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo; - if (chip->chip_id == RTL8852A) { - pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo); + if (ver->fcxtdma == 1) { + pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1); + } else if (ver->fcxtdma == 3) { + pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3); } else { - pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo_v1); + goto err; } - pcinfo->req_fver = chip->fcxtdma_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxtdma; break; case BTC_RPT_TYPE_SLOT: pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo; pfinfo = &pfwinfo->rpt_fbtc_slots.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo); - pcinfo->req_fver = chip->fcxslots_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxslots; break; case BTC_RPT_TYPE_CYSTA: pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo; - if (chip->chip_id == RTL8852A) { - pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo; - pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo; - rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta); - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo); + pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; + if (ver->fcxcysta == 2) { + pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v2; + pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v2); + } else if (ver->fcxcysta == 3) { + pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v3; + pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v3); + } else if (ver->fcxcysta == 4) { + pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v4; + pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v4); } else { - pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo_v1; - pcysta_v1 = &pfwinfo->rpt_fbtc_cysta.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo_v1); + goto err; } - pcinfo->req_fver = chip->fcxcysta_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxcysta; break; case BTC_RPT_TYPE_STEP: pcinfo = &pfwinfo->rpt_fbtc_step.cinfo; - if (chip->chip_id == RTL8852A) { - pfinfo = &pfwinfo->rpt_fbtc_step.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.step[0]) * + if (ver->fcxstep == 2) { + pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v2; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) * trace_step + - offsetof(struct rtw89_btc_fbtc_steps, step); - } else { - pfinfo = &pfwinfo->rpt_fbtc_step.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo_v1.step[0]) * + offsetof(struct rtw89_btc_fbtc_steps_v2, step); + } else if (ver->fcxstep == 3) { + pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v3; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v3.step[0]) * trace_step + - offsetof(struct rtw89_btc_fbtc_steps_v1, step); + offsetof(struct rtw89_btc_fbtc_steps_v3, step); + } else { + goto err; } - pcinfo->req_fver = chip->fcxstep_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxstep; break; case BTC_RPT_TYPE_NULLSTA: pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo; - if (chip->chip_id == RTL8852A) { + if (ver->fcxnullsta == 1) { pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo); + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v1); + } else if (ver->fcxnullsta == 2) { + pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v2; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v2); } else { - pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo_v1); + goto err; } - pcinfo->req_fver = chip->fcxnullsta_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxnullsta; break; case BTC_RPT_TYPE_MREG: pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo; pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo); - pcinfo->req_fver = chip->fcxmreg_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxmreg; break; case BTC_RPT_TYPE_GPIO_DBG: pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo; pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo); - pcinfo->req_fver = chip->fcxgpiodbg_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxgpiodbg; break; case BTC_RPT_TYPE_BT_VER: pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo; pfinfo = &pfwinfo->rpt_fbtc_btver.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo); - pcinfo->req_fver = chip->fcxbtver_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxbtver; break; case BTC_RPT_TYPE_BT_SCAN: pcinfo = &pfwinfo->rpt_fbtc_btscan.cinfo; pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo); - pcinfo->req_fver = chip->fcxbtscan_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxbtscan; break; case BTC_RPT_TYPE_BT_AFH: pcinfo = &pfwinfo->rpt_fbtc_btafh.cinfo; - pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo); - pcinfo->req_fver = chip->fcxbtafh_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + if (ver->fcxbtafh == 1) { + pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v1; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v1); + } else if (ver->fcxbtafh == 2) { + pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v2; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v2); + } else { + goto err; + } + pcinfo->req_fver = ver->fcxbtafh; break; case BTC_RPT_TYPE_BT_DEVICE: pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo; pfinfo = &pfwinfo->rpt_fbtc_btdev.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btdev.finfo); - pcinfo->req_fver = chip->fcxbtdevinfo_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxbtdevinfo; break; default: pfwinfo->err[BTFRE_UNDEF_TYPE]++; return 0; } + pcinfo->rx_len = rpt_len; + pcinfo->rx_cnt++; + if (rpt_len != pcinfo->req_len) { if (rpt_type < BTC_RPT_TYPE_MAX) pfwinfo->len_mismch |= (0x1 << rpt_type); @@ -1102,235 +1115,257 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, memcpy(pfinfo, rpt_content, pcinfo->req_len); pcinfo->valid = 1; - if (rpt_type == BTC_RPT_TYPE_TDMA && chip->chip_id == RTL8852A) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): check %d %zu\n", __func__, - BTC_DCNT_TDMA_NONSYNC, sizeof(dm->tdma_now)); - - if (memcmp(&dm->tdma_now, &pfwinfo->rpt_fbtc_tdma.finfo, - sizeof(dm->tdma_now)) != 0) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d tdma_now %x %x %x %x %x %x %x %x\n", - __func__, BTC_DCNT_TDMA_NONSYNC, - dm->tdma_now.type, dm->tdma_now.rxflctrl, - dm->tdma_now.txpause, dm->tdma_now.wtgle_n, - dm->tdma_now.leak_n, dm->tdma_now.ext_ctrl, - dm->tdma_now.rxflctrl_role, - dm->tdma_now.option_ctrl); - - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d rpt_fbtc_tdma %x %x %x %x %x %x %x %x\n", - __func__, BTC_DCNT_TDMA_NONSYNC, - pfwinfo->rpt_fbtc_tdma.finfo.type, - pfwinfo->rpt_fbtc_tdma.finfo.rxflctrl, - pfwinfo->rpt_fbtc_tdma.finfo.txpause, - pfwinfo->rpt_fbtc_tdma.finfo.wtgle_n, - pfwinfo->rpt_fbtc_tdma.finfo.leak_n, - pfwinfo->rpt_fbtc_tdma.finfo.ext_ctrl, - pfwinfo->rpt_fbtc_tdma.finfo.rxflctrl_role, - pfwinfo->rpt_fbtc_tdma.finfo.option_ctrl); - } + switch (rpt_type) { + case BTC_RPT_TYPE_CTRL: + if (ver->fcxbtcrpt == 1) { + prpt->v1 = pfwinfo->rpt_ctrl.finfo.v1; + btc->fwinfo.rpt_en_map = prpt->v1.rpt_enable; + wl->ver_info.fw_coex = prpt->v1.wl_fw_coex_ver; + wl->ver_info.fw = prpt->v1.wl_fw_ver; + dm->wl_fw_cx_offload = !!prpt->v1.wl_fw_cx_offload; + + _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, + pfwinfo->event[BTF_EVNT_RPT]); + + /* To avoid I/O if WL LPS or power-off */ + if (wl->status.map.lps != BTC_LPS_RF_OFF && + !wl->status.map.rf_off) { + rtwdev->chip->ops->btc_update_bt_cnt(rtwdev); + _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + + btc->cx.cnt_bt[BTC_BCNT_POLUT] = + rtw89_mac_get_plt_cnt(rtwdev, + RTW89_MAC_0); + } + } else if (ver->fcxbtcrpt == 4) { + prpt->v4 = pfwinfo->rpt_ctrl.finfo.v4; + btc->fwinfo.rpt_en_map = le32_to_cpu(prpt->v4.rpt_info.en); + wl->ver_info.fw_coex = le32_to_cpu(prpt->v4.wl_fw_info.cx_ver); + wl->ver_info.fw = le32_to_cpu(prpt->v4.wl_fw_info.fw_ver); + dm->wl_fw_cx_offload = !!le32_to_cpu(prpt->v4.wl_fw_info.cx_offload); + + for (i = RTW89_PHY_0; i < RTW89_PHY_MAX; i++) + memcpy(&dm->gnt.band[i], &prpt->v4.gnt_val[i], + sizeof(dm->gnt.band[i])); + + btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_TX]); + btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_RX]); + btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_TX]); + btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_RX]); + btc->cx.cnt_bt[BTC_BCNT_POLUT] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_POLLUTED]); - _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, - memcmp(&dm->tdma_now, - &pfwinfo->rpt_fbtc_tdma.finfo, - sizeof(dm->tdma_now))); - } else if (rpt_type == BTC_RPT_TYPE_TDMA) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): check %d %zu\n", __func__, - BTC_DCNT_TDMA_NONSYNC, sizeof(dm->tdma_now)); - - if (memcmp(&dm->tdma_now, &pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma, - sizeof(dm->tdma_now)) != 0) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d tdma_now %x %x %x %x %x %x %x %x\n", - __func__, BTC_DCNT_TDMA_NONSYNC, - dm->tdma_now.type, dm->tdma_now.rxflctrl, - dm->tdma_now.txpause, dm->tdma_now.wtgle_n, - dm->tdma_now.leak_n, dm->tdma_now.ext_ctrl, - dm->tdma_now.rxflctrl_role, - dm->tdma_now.option_ctrl); - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d rpt_fbtc_tdma %x %x %x %x %x %x %x %x\n", - __func__, BTC_DCNT_TDMA_NONSYNC, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.type, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.rxflctrl, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.txpause, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.wtgle_n, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.leak_n, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.ext_ctrl, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.rxflctrl_role, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.option_ctrl); - } + _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, + pfwinfo->event[BTF_EVNT_RPT]); - _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, - memcmp(&dm->tdma_now, - &pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma, - sizeof(dm->tdma_now))); - } + if (le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0) + bt->rfk_info.map.timeout = 1; + else + bt->rfk_info.map.timeout = 0; + + dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout; + } else if (ver->fcxbtcrpt == 5) { + prpt->v5 = pfwinfo->rpt_ctrl.finfo.v5; + pfwinfo->rpt_en_map = le32_to_cpu(prpt->v5.rpt_info.en); + wl->ver_info.fw_coex = le32_to_cpu(prpt->v5.rpt_info.cx_ver); + wl->ver_info.fw = le32_to_cpu(prpt->v5.rpt_info.fw_ver); + dm->wl_fw_cx_offload = 0; + + for (i = RTW89_PHY_0; i < RTW89_PHY_MAX; i++) + memcpy(&dm->gnt.band[i], &prpt->v5.gnt_val[i][0], + sizeof(dm->gnt.band[i])); + + btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_TX]); + btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_RX]); + btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_TX]); + btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_RX]); + btc->cx.cnt_bt[BTC_BCNT_POLUT] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_POLLUTED]); + + _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, + pfwinfo->event[BTF_EVNT_RPT]); - if (rpt_type == BTC_RPT_TYPE_SLOT) { + dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout; + } else { + goto err; + } + break; + case BTC_RPT_TYPE_TDMA: + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): check %d %zu\n", __func__, + BTC_DCNT_TDMA_NONSYNC, + sizeof(dm->tdma_now)); + if (ver->fcxtdma == 1) + _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, + memcmp(&dm->tdma_now, + &pfwinfo->rpt_fbtc_tdma.finfo.v1, + sizeof(dm->tdma_now))); + else if (ver->fcxtdma == 3) + _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, + memcmp(&dm->tdma_now, + &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma, + sizeof(dm->tdma_now))); + else + goto err; + break; + case BTC_RPT_TYPE_SLOT: rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): check %d %zu\n", __func__, BTC_DCNT_SLOT_NONSYNC, sizeof(dm->slot_now)); - - if (memcmp(dm->slot_now, pfwinfo->rpt_fbtc_slots.finfo.slot, - sizeof(dm->slot_now)) != 0) { - for (i = 0; i < CXST_MAX; i++) { - rtp_slot = - &pfwinfo->rpt_fbtc_slots.finfo.slot[i]; - if (memcmp(&dm->slot_now[i], rtp_slot, - sizeof(dm->slot_now[i])) != 0) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d slot_now[%d] dur=0x%04x tbl=%08x type=0x%04x\n", - __func__, - BTC_DCNT_SLOT_NONSYNC, i, - dm->slot_now[i].dur, - dm->slot_now[i].cxtbl, - dm->slot_now[i].cxtype); - - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d rpt_fbtc_slots[%d] dur=0x%04x tbl=%08x type=0x%04x\n", - __func__, - BTC_DCNT_SLOT_NONSYNC, i, - rtp_slot->dur, - rtp_slot->cxtbl, - rtp_slot->cxtype); - } - } - } _chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC, memcmp(dm->slot_now, pfwinfo->rpt_fbtc_slots.finfo.slot, sizeof(dm->slot_now))); - } + break; + case BTC_RPT_TYPE_CYSTA: + if (ver->fcxcysta == 2) { + if (le16_to_cpu(pcysta->v2.cycles) < BTC_CYSTA_CHK_PERIOD) + break; + /* Check Leak-AP */ + if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) != 0 && + le32_to_cpu(pcysta->v2.leakrx_cnt) != 0 && dm->tdma_now.rxflctrl) { + if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) < + BTC_LEAK_AP_TH * le32_to_cpu(pcysta->v2.leakrx_cnt)) + dm->leak_ap = 1; + } - if (rpt_type == BTC_RPT_TYPE_CYSTA && chip->chip_id == RTL8852A && - pcysta->cycles >= BTC_CYSTA_CHK_PERIOD) { - /* Check Leak-AP */ - if (pcysta->slot_cnt[CXST_LK] != 0 && - pcysta->leakrx_cnt != 0 && dm->tdma_now.rxflctrl) { - if (pcysta->slot_cnt[CXST_LK] < - BTC_LEAK_AP_TH * pcysta->leakrx_cnt) - dm->leak_ap = 1; - } + /* Check diff time between WL slot and W1/E2G slot */ + if (dm->tdma_now.type == CXTDMA_OFF && + dm->tdma_now.ext_ctrl == CXECTL_EXT) + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_E2G].dur); + else + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); - /* Check diff time between WL slot and W1/E2G slot */ - if (dm->tdma_now.type == CXTDMA_OFF && - dm->tdma_now.ext_ctrl == CXECTL_EXT) - wl_slot_set = le16_to_cpu(dm->slot_now[CXST_E2G].dur); - else - wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); + if (le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) > wl_slot_set) { + diff_t = le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) - wl_slot_set; + _chk_btc_err(rtwdev, + BTC_DCNT_WL_SLOT_DRIFT, diff_t); + } - if (pcysta->tavg_cycle[CXT_WL] > wl_slot_set) { - diff_t = pcysta->tavg_cycle[CXT_WL] - wl_slot_set; - _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); - } + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, + le32_to_cpu(pcysta->v2.slot_cnt[CXST_W1])); + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, + le32_to_cpu(pcysta->v2.slot_cnt[CXST_B1])); + _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, + le16_to_cpu(pcysta->v2.cycles)); + } else if (ver->fcxcysta == 3) { + if (le16_to_cpu(pcysta->v3.cycles) < BTC_CYSTA_CHK_PERIOD) + break; - _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_W1]); - _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_B1]); - _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, (u32)pcysta->cycles); - } else if (rpt_type == BTC_RPT_TYPE_CYSTA && pcysta_v1 && - le16_to_cpu(pcysta_v1->cycles) >= BTC_CYSTA_CHK_PERIOD) { - cnt_leak_slot = le32_to_cpu(pcysta_v1->slot_cnt[CXST_LK]); - cnt_rx_imr = le32_to_cpu(pcysta_v1->leak_slot.cnt_rximr); - /* Check Leak-AP */ - if (cnt_leak_slot != 0 && cnt_rx_imr != 0 && - dm->tdma_now.rxflctrl) { - if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr) - dm->leak_ap = 1; - } + cnt_leak_slot = le32_to_cpu(pcysta->v3.slot_cnt[CXST_LK]); + cnt_rx_imr = le32_to_cpu(pcysta->v3.leak_slot.cnt_rximr); - /* Check diff time between real WL slot and W1 slot */ - if (dm->tdma_now.type == CXTDMA_OFF) { - wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); - wl_slot_real = le16_to_cpu(pcysta_v1->cycle_time.tavg[CXT_WL]); - if (wl_slot_real > wl_slot_set) { - diff_t = wl_slot_real - wl_slot_set; - _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); + /* Check Leak-AP */ + if (cnt_leak_slot != 0 && cnt_rx_imr != 0 && + dm->tdma_now.rxflctrl) { + if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr) + dm->leak_ap = 1; } - } - /* Check diff time between real BT slot and EBT/E5G slot */ - if (dm->tdma_now.type == CXTDMA_OFF && - dm->tdma_now.ext_ctrl == CXECTL_EXT && - btc->bt_req_len != 0) { - bt_slot_real = le16_to_cpu(pcysta_v1->cycle_time.tavg[CXT_BT]); + /* Check diff time between real WL slot and W1 slot */ + if (dm->tdma_now.type == CXTDMA_OFF) { + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); + wl_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_WL]); + if (wl_slot_real > wl_slot_set) { + diff_t = wl_slot_real - wl_slot_set; + _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); + } + } - if (btc->bt_req_len > bt_slot_real) { - diff_t = btc->bt_req_len - bt_slot_real; - _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t); + /* Check diff time between real BT slot and EBT/E5G slot */ + if (dm->tdma_now.type == CXTDMA_OFF && + dm->tdma_now.ext_ctrl == CXECTL_EXT && + btc->bt_req_len != 0) { + bt_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_BT]); + if (btc->bt_req_len > bt_slot_real) { + diff_t = btc->bt_req_len - bt_slot_real; + _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t); + } } - } - _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, - le32_to_cpu(pcysta_v1->slot_cnt[CXST_W1])); - _chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, - le32_to_cpu(pcysta_v1->slot_cnt[CXST_B1])); - _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, - (u32)le16_to_cpu(pcysta_v1->cycles)); - } + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, + le32_to_cpu(pcysta->v3.slot_cnt[CXST_W1])); + _chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, + le32_to_cpu(pcysta->v3.slot_cnt[CXST_B1])); + _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, + le16_to_cpu(pcysta->v3.cycles)); + } else if (ver->fcxcysta == 4) { + if (le16_to_cpu(pcysta->v4.cycles) < BTC_CYSTA_CHK_PERIOD) + break; - if (rpt_type == BTC_RPT_TYPE_CTRL && chip->chip_id == RTL8852A) { - prpt = &pfwinfo->rpt_ctrl.finfo; - btc->fwinfo.rpt_en_map = prpt->rpt_enable; - wl->ver_info.fw_coex = prpt->wl_fw_coex_ver; - wl->ver_info.fw = prpt->wl_fw_ver; - dm->wl_fw_cx_offload = !!prpt->wl_fw_cx_offload; + cnt_leak_slot = le16_to_cpu(pcysta->v4.slot_cnt[CXST_LK]); + cnt_rx_imr = le32_to_cpu(pcysta->v4.leak_slot.cnt_rximr); - _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, - pfwinfo->event[BTF_EVNT_RPT]); + /* Check Leak-AP */ + if (cnt_leak_slot != 0 && cnt_rx_imr != 0 && + dm->tdma_now.rxflctrl) { + if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr) + dm->leak_ap = 1; + } - /* To avoid I/O if WL LPS or power-off */ - if (wl->status.map.lps != BTC_LPS_RF_OFF && !wl->status.map.rf_off) { - rtwdev->chip->ops->btc_update_bt_cnt(rtwdev); - _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + /* Check diff time between real WL slot and W1 slot */ + if (dm->tdma_now.type == CXTDMA_OFF) { + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); + wl_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_WL]); + if (wl_slot_real > wl_slot_set) { + diff_t = wl_slot_real - wl_slot_set; + _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); + } + } - btc->cx.cnt_bt[BTC_BCNT_POLUT] = - rtw89_mac_get_plt_cnt(rtwdev, RTW89_MAC_0); - } - } else if (rpt_type == BTC_RPT_TYPE_CTRL) { - prpt_v1 = &pfwinfo->rpt_ctrl.finfo_v1; - btc->fwinfo.rpt_en_map = le32_to_cpu(prpt_v1->rpt_info.en); - wl->ver_info.fw_coex = le32_to_cpu(prpt_v1->wl_fw_info.cx_ver); - wl->ver_info.fw = le32_to_cpu(prpt_v1->wl_fw_info.fw_ver); - dm->wl_fw_cx_offload = !!le32_to_cpu(prpt_v1->wl_fw_info.cx_offload); - - for (i = RTW89_PHY_0; i < RTW89_PHY_MAX; i++) - memcpy(&dm->gnt.band[i], &prpt_v1->gnt_val[i], - sizeof(dm->gnt.band[i])); - - btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_HI_TX]); - btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_HI_RX]); - btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_LO_TX]); - btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_LO_RX]); - btc->cx.cnt_bt[BTC_BCNT_POLUT] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_POLLUTED]); - - _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); - _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, - pfwinfo->event[BTF_EVNT_RPT]); - - if (le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0) - bt->rfk_info.map.timeout = 1; - else - bt->rfk_info.map.timeout = 0; + /* Check diff time between real BT slot and EBT/E5G slot */ + if (dm->tdma_now.type == CXTDMA_OFF && + dm->tdma_now.ext_ctrl == CXECTL_EXT && + btc->bt_req_len != 0) { + bt_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_BT]); - dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout; - } + if (btc->bt_req_len > bt_slot_real) { + diff_t = btc->bt_req_len - bt_slot_real; + _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t); + } + } - if (rpt_type >= BTC_RPT_TYPE_BT_VER && - rpt_type <= BTC_RPT_TYPE_BT_DEVICE) + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, + le16_to_cpu(pcysta->v4.slot_cnt[CXST_W1])); + _chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, + le16_to_cpu(pcysta->v4.slot_cnt[CXST_B1])); + _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, + le16_to_cpu(pcysta->v4.cycles)); + } else { + goto err; + } + break; + case BTC_RPT_TYPE_BT_VER: + case BTC_RPT_TYPE_BT_SCAN: + case BTC_RPT_TYPE_BT_AFH: + case BTC_RPT_TYPE_BT_DEVICE: _update_bt_report(rtwdev, rpt_type, pfinfo); - + break; + } return (rpt_len + BTC_RPT_HDR_SIZE); + +err: + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): Undefined version for type=%d\n", __func__, rpt_type); + return 0; } static void _parse_btc_report(struct rtw89_dev *rtwdev, struct rtw89_btc_btf_fwinfo *pfwinfo, u8 *pbuf, u32 buf_len) { - const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_btc_ver *ver = rtwdev->btc.ver; struct rtw89_btc_prpt *btc_prpt = NULL; u32 index = 0, rpt_len = 0; @@ -1340,7 +1375,7 @@ static void _parse_btc_report(struct rtw89_dev *rtwdev, while (pbuf) { btc_prpt = (struct rtw89_btc_prpt *)&pbuf[index]; - if (index + 2 >= chip->btc_fwinfo_buf) + if (index + 2 >= ver->info_buf) break; /* At least 3 bytes: type(1) & len(2) */ rpt_len = le16_to_cpu(btc_prpt->len); @@ -1358,12 +1393,12 @@ static void _parse_btc_report(struct rtw89_dev *rtwdev, static void _append_tdma(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_btf_tlv *tlv; struct rtw89_btc_fbtc_tdma *v; - struct rtw89_btc_fbtc_tdma_v1 *v1; + struct rtw89_btc_fbtc_tdma_v3 *v3; u16 len = btc->policy_len; if (!btc->update_policy_force && @@ -1376,17 +1411,17 @@ static void _append_tdma(struct rtw89_dev *rtwdev) tlv = (struct rtw89_btc_btf_tlv *)&btc->policy[len]; tlv->type = CXPOLICY_TDMA; - if (chip->chip_id == RTL8852A) { + if (ver->fcxtdma == 1) { v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0]; tlv->len = sizeof(*v); memcpy(v, &dm->tdma, sizeof(*v)); - btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v); + btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v); } else { - tlv->len = sizeof(*v1); - v1 = (struct rtw89_btc_fbtc_tdma_v1 *)&tlv->val[0]; - v1->fver = chip->fcxtdma_ver; - v1->tdma = dm->tdma; - btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v1); + tlv->len = sizeof(*v3); + v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0]; + v3->fver = ver->fcxtdma; + memcpy(&v3->tdma, &dm->tdma, sizeof(v3->tdma)); + btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3); } rtw89_debug(rtwdev, RTW89_DBG_BTC, @@ -1441,22 +1476,169 @@ static void _append_slot(struct rtw89_dev *rtwdev) __func__, cnt); } +static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) +{ + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; + u32 bit_map = 0; + + switch (rpt_map) { + case RPT_EN_TDMA: + bit_map = BIT(0); + break; + case RPT_EN_CYCLE: + bit_map = BIT(1); + break; + case RPT_EN_MREG: + bit_map = BIT(2); + break; + case RPT_EN_BT_VER_INFO: + bit_map = BIT(3); + break; + case RPT_EN_BT_SCAN_INFO: + bit_map = BIT(4); + break; + case RPT_EN_BT_DEVICE_INFO: + switch (ver->frptmap) { + case 0: + case 1: + case 2: + bit_map = BIT(6); + break; + case 3: + bit_map = BIT(5); + break; + default: + break; + } + break; + case RPT_EN_BT_AFH_MAP: + switch (ver->frptmap) { + case 0: + case 1: + case 2: + bit_map = BIT(5); + break; + case 3: + bit_map = BIT(6); + break; + default: + break; + } + break; + case RPT_EN_BT_AFH_MAP_LE: + switch (ver->frptmap) { + case 2: + bit_map = BIT(8); + break; + case 3: + bit_map = BIT(7); + break; + default: + break; + } + break; + case RPT_EN_FW_STEP_INFO: + switch (ver->frptmap) { + case 1: + case 2: + bit_map = BIT(7); + break; + case 3: + bit_map = BIT(8); + break; + default: + break; + } + break; + case RPT_EN_TEST: + bit_map = BIT(31); + break; + case RPT_EN_WL_ALL: + switch (ver->frptmap) { + case 0: + case 1: + case 2: + bit_map = GENMASK(2, 0); + break; + case 3: + bit_map = GENMASK(2, 0) | BIT(8); + break; + default: + break; + } + break; + case RPT_EN_BT_ALL: + switch (ver->frptmap) { + case 0: + case 1: + bit_map = GENMASK(6, 3); + break; + case 2: + bit_map = GENMASK(6, 3) | BIT(8); + break; + case 3: + bit_map = GENMASK(7, 3); + break; + default: + break; + } + break; + case RPT_EN_ALL: + switch (ver->frptmap) { + case 0: + bit_map = GENMASK(6, 0); + break; + case 1: + bit_map = GENMASK(7, 0); + break; + case 2: + case 3: + bit_map = GENMASK(8, 0); + break; + default: + break; + } + break; + case RPT_EN_MONITER: + switch (ver->frptmap) { + case 0: + case 1: + bit_map = GENMASK(6, 2); + break; + case 2: + bit_map = GENMASK(6, 2) | BIT(8); + break; + case 3: + bit_map = GENMASK(8, 2); + break; + default: + break; + } + break; + } + + return bit_map; +} + static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev, u32 rpt_map, bool rpt_state) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *fwinfo = &btc->fwinfo; struct rtw89_btc_btf_set_report r = {0}; - u32 val = 0; + u32 val, bit_map; + + bit_map = rtw89_btc_fw_rpt_ver(rtwdev, rpt_map); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): rpt_map=%x, rpt_state=%x\n", __func__, rpt_map, rpt_state); if (rpt_state) - val = fwinfo->rpt_en_map | rpt_map; + val = fwinfo->rpt_en_map | bit_map; else - val = fwinfo->rpt_en_map & ~rpt_map; + val = fwinfo->rpt_en_map & ~bit_map; if (val == fwinfo->rpt_en_map) return; @@ -1593,16 +1775,17 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type, static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) { - const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; switch (type) { case CXDRVINFO_INIT: rtw89_fw_h2c_cxdrv_init(rtwdev); break; case CXDRVINFO_ROLE: - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) rtw89_fw_h2c_cxdrv_role(rtwdev); - else + else if (ver->fwlrole == 1) rtw89_fw_h2c_cxdrv_role_v1(rtwdev); break; case CXDRVINFO_CTRL: @@ -1892,6 +2075,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_bt_link_info *b = &bt->link_info; @@ -1905,7 +2089,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) if (btc->ctrl.manual || wl->status.map.scan) return; - if (chip->chip_id == RTL8852A) { + if (ver->fwlrole == 0) { mode = wl_rinfo->link_mode; connect_cnt = wl_rinfo->connect_cnt; } else { @@ -1924,13 +2108,13 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) r = &wl_rinfo->active_role[i]; r1 = &wl_rinfo_v1->active_role_v1[i]; - if (chip->chip_id == RTL8852A && + if (ver->fwlrole == 0 && (r->role == RTW89_WIFI_ROLE_P2P_GO || r->role == RTW89_WIFI_ROLE_P2P_CLIENT)) { ch = r->ch; bw = r->bw; break; - } else if (chip->chip_id != RTL8852A && + } else if (ver->fwlrole == 1 && (r1->role == RTW89_WIFI_ROLE_P2P_GO || r1->role == RTW89_WIFI_ROLE_P2P_CLIENT)) { ch = r1->ch; @@ -1945,12 +2129,12 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) r = &wl_rinfo->active_role[i]; r1 = &wl_rinfo_v1->active_role_v1[i]; - if (chip->chip_id == RTL8852A && + if (ver->fwlrole == 0 && r->connected && r->band == RTW89_BAND_2G) { ch = r->ch; bw = r->bw; break; - } else if (chip->chip_id != RTL8852A && + } else if (ver->fwlrole == 1 && r1->connected && r1->band == RTW89_BAND_2G) { ch = r1->ch; bw = r1->bw; @@ -3398,8 +3582,8 @@ static void _action_wl_rfk(struct rtw89_dev *rtwdev) static void _set_btg_ctrl(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info; struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1; @@ -3410,7 +3594,7 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) if (btc->ctrl.manual) return; - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -3503,8 +3687,8 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_wl_info *wl = &cx->wl; @@ -3524,7 +3708,7 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) if (btc->ctrl.manual) return; - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -3572,8 +3756,8 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) static void _set_bt_rx_agc(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info; struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1; @@ -3581,7 +3765,7 @@ static void _set_bt_rx_agc(struct rtw89_dev *rtwdev) bool bt_hi_lna_rx = false; u8 mode; - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -4445,8 +4629,8 @@ static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev) static void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &rtwdev->btc.dm; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_wl_info *wl = &btc->cx.wl; @@ -4461,7 +4645,7 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) _update_dm_step(rtwdev, reason); _update_btc_state_map(rtwdev); - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -4583,9 +4767,9 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) break; case BTC_WLINK_2G_SCC: bt->scan_rx_low_pri = true; - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) _action_wl_2g_scc(rtwdev); - else if (chip->chip_id == RTL8852C) + else if (ver->fwlrole == 1) _action_wl_2g_scc_v1(rtwdev); break; case BTC_WLINK_2G_MCC: @@ -4690,7 +4874,7 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode) _write_scbd(rtwdev, BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true); _update_bt_scbd(rtwdev, true); - if (rtw89_mac_get_ctrl_path(rtwdev) && chip->chip_id == RTL8852A) { + if (rtw89_mac_get_ctrl_path(rtwdev)) { rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): PTA owner warning!!\n", __func__); @@ -5000,11 +5184,6 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) a2dp->sink = btinfo.hb3.a2dp_sink; - if (b->profile_cnt.now || b->status.map.ble_connect) - rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 1); - else - rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 0); - if (!a2dp->exist_last && a2dp->exist) { a2dp->vendor_id = 0; a2dp->flush_time = 0; @@ -5014,12 +5193,6 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) RTW89_COEX_BT_DEVINFO_WORK_PERIOD); } - if (a2dp->exist && (a2dp->flush_time == 0 || a2dp->vendor_id == 0 || - a2dp->play_latency == 1)) - rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 1); - else - rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 0); - _run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO); } @@ -5034,10 +5207,10 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif struct rtw89_sta *rtwsta, enum btc_role_state state) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); - const struct rtw89_chip_info *chip = rtwdev->chip; struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_link_info r = {0}; struct rtw89_btc_wl_link_info *wlinfo = NULL; @@ -5101,7 +5274,7 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif wlinfo = &wl->link_info[r.pid]; memcpy(wlinfo, &r, sizeof(*wlinfo)); - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) _update_wl_info(rtwdev); else _update_wl_info_v1(rtwdev); @@ -5152,8 +5325,7 @@ void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_sta if (rf_state == BTC_RFCTRL_WL_ON) { btc->dm.cnt_dm[BTC_DCNT_BTCNT_FREEZE] = 0; - rtw89_btc_fw_en_rpt(rtwdev, - RPT_EN_MREG | RPT_EN_BT_VER_INFO, true); + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, true); val = BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG; _write_scbd(rtwdev, val, true); _update_bt_scbd(rtwdev, true); @@ -5618,8 +5790,8 @@ static void _show_wl_role_info(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_wl_info *wl = &cx->wl; struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info; @@ -5631,7 +5803,7 @@ static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m) seq_puts(m, "========== [WL Status] ==========\n"); - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -5714,12 +5886,14 @@ static void _show_bt_profile_info(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_bt_info *bt = &cx->bt; struct rtw89_btc_wl_info *wl = &cx->wl; struct rtw89_btc_module *module = &btc->mdinfo; struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; u8 *afh = bt_linfo->afh_map; + u8 *afh_le = bt_linfo->afh_map_le; if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT)) return; @@ -5769,6 +5943,12 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) afh[0], afh[1], afh[2], afh[3], afh[4], afh[5], afh[6], afh[7], afh[8], afh[9]); + if (ver->fcxbtafh == 2 && bt_linfo->status.map.ble_connect) + seq_printf(m, + "LE[%02x%02x_%02x_%02x%02x]", + afh_le[0], afh_le[1], afh_le[2], + afh_le[3], afh_le[4]); + seq_printf(m, "wl_ch_map[en:%d/ch:%d/bw:%d]\n", wl->afh_info.en, wl->afh_info.ch, wl->afh_info.bw); @@ -5800,6 +5980,29 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) "[trx_req_cnt]", cx->cnt_bt[BTC_BCNT_HIPRI_RX], cx->cnt_bt[BTC_BCNT_HIPRI_TX], cx->cnt_bt[BTC_BCNT_LOPRI_RX], cx->cnt_bt[BTC_BCNT_LOPRI_TX], cx->cnt_bt[BTC_BCNT_POLUT]); + + if (bt->enable.now && bt->ver_info.fw == 0) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, false); + + if (bt_linfo->profile_cnt.now || bt_linfo->status.map.ble_connect) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, false); + + if (ver->fcxbtafh == 2 && bt_linfo->status.map.ble_connect) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP_LE, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP_LE, false); + + if (bt_linfo->a2dp_desc.exist && + (bt_linfo->a2dp_desc.flush_time == 0 || + bt_linfo->a2dp_desc.vendor_id == 0 || + bt_linfo->a2dp_desc.play_latency == 1)) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, false); } #define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e @@ -5807,6 +6010,7 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) #define CASE_BTC_POLICY_STR(e) \ case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e #define CASE_BTC_SLOT_STR(e) case CXST_ ## e: return #e +#define CASE_BTC_EVT_STR(e) case CXEVNT_## e: return #e static const char *steps_to_str(u16 step) { @@ -5947,6 +6151,40 @@ static const char *id_to_slot(u32 id) } } +static const char *id_to_evt(u32 id) +{ + switch (id) { + CASE_BTC_EVT_STR(TDMA_ENTRY); + CASE_BTC_EVT_STR(WL_TMR); + CASE_BTC_EVT_STR(B1_TMR); + CASE_BTC_EVT_STR(B2_TMR); + CASE_BTC_EVT_STR(B3_TMR); + CASE_BTC_EVT_STR(B4_TMR); + CASE_BTC_EVT_STR(W2B_TMR); + CASE_BTC_EVT_STR(B2W_TMR); + CASE_BTC_EVT_STR(BCN_EARLY); + CASE_BTC_EVT_STR(A2DP_EMPTY); + CASE_BTC_EVT_STR(LK_END); + CASE_BTC_EVT_STR(RX_ISR); + CASE_BTC_EVT_STR(RX_FC0); + CASE_BTC_EVT_STR(RX_FC1); + CASE_BTC_EVT_STR(BT_RELINK); + CASE_BTC_EVT_STR(BT_RETRY); + CASE_BTC_EVT_STR(E2G); + CASE_BTC_EVT_STR(E5G); + CASE_BTC_EVT_STR(EBT); + CASE_BTC_EVT_STR(ENULL); + CASE_BTC_EVT_STR(DRV_WLK); + CASE_BTC_EVT_STR(BCN_OK); + CASE_BTC_EVT_STR(BT_CHANGE); + CASE_BTC_EVT_STR(EBT_EXTEND); + CASE_BTC_EVT_STR(E2G_NULL1); + CASE_BTC_EVT_STR(B1FDD_TMR); + default: + return "unknown"; + } +} + static void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data, u8 len, u8 seg_len, u8 start_idx, u8 ring_len) @@ -6045,21 +6283,27 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; - struct rtw89_btc_fbtc_cysta *pcysta; - struct rtw89_btc_fbtc_cysta_v1 *pcysta_v1; + union rtw89_btc_fbtc_cysta_info *pcysta; u32 except_cnt, exception_map; - if (chip->chip_id == RTL8852A) { - pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; - except_cnt = le32_to_cpu(pcysta->except_cnt); - exception_map = le32_to_cpu(pcysta->exception); + pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; + if (ver->fcxcysta == 2) { + pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2; + except_cnt = le32_to_cpu(pcysta->v2.except_cnt); + exception_map = le32_to_cpu(pcysta->v2.exception); + } else if (ver->fcxcysta == 3) { + pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3; + except_cnt = le32_to_cpu(pcysta->v3.except_cnt); + exception_map = le32_to_cpu(pcysta->v3.except_map); + } else if (ver->fcxcysta == 4) { + pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4; + except_cnt = pcysta->v4.except_cnt; + exception_map = le32_to_cpu(pcysta->v4.except_map); } else { - pcysta_v1 = &pfwinfo->rpt_fbtc_cysta.finfo_v1; - except_cnt = le32_to_cpu(pcysta_v1->except_cnt); - exception_map = le32_to_cpu(pcysta_v1->except_map); + return; } if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 && except_cnt == 0 && @@ -6097,23 +6341,20 @@ static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_fbtc_tdma(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; struct rtw89_btc_fbtc_tdma *t = NULL; - struct rtw89_btc_fbtc_slot *s = NULL; - struct rtw89_btc_dm *dm = &btc->dm; - u8 i, cnt = 0; pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo; if (!pcinfo->valid) return; - if (chip->chip_id == RTL8852A) - t = &pfwinfo->rpt_fbtc_tdma.finfo; + if (ver->fcxtdma == 1) + t = &pfwinfo->rpt_fbtc_tdma.finfo.v1; else - t = &pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma; + t = &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma; seq_printf(m, " %-15s : ", "[tdma_policy]"); @@ -6130,75 +6371,42 @@ static void _show_fbtc_tdma(struct rtw89_dev *rtwdev, struct seq_file *m) "policy_type:%d", (u32)btc->policy_type); - s = pfwinfo->rpt_fbtc_slots.finfo.slot; - - for (i = 0; i < CXST_MAX; i++) { - if (dm->update_slot_map == BIT(CXST_MAX) - 1) - break; - - if (!(dm->update_slot_map & BIT(i))) - continue; - - if (cnt % 6 == 0) - seq_printf(m, - " %-15s : %d[%d/0x%x/%d]", - "[slot_policy]", - (u32)i, - s[i].dur, s[i].cxtbl, s[i].cxtype); - else - seq_printf(m, - ", %d[%d/0x%x/%d]", - (u32)i, - s[i].dur, s[i].cxtbl, s[i].cxtype); - if (cnt % 6 == 5) - seq_puts(m, "\n"); - cnt++; - } seq_puts(m, "\n"); } static void _show_fbtc_slots(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; - struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_slots *pslots = NULL; - struct rtw89_btc_fbtc_slot s; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_fbtc_slot *s; u8 i = 0; - pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo; - if (!pcinfo->valid) - return; - - pslots = &pfwinfo->rpt_fbtc_slots.finfo; - for (i = 0; i < CXST_MAX; i++) { - s = pslots->slot[i]; + s = &dm->slot_now[i]; if (i % 6 == 0) seq_printf(m, " %-15s : %02d[%03d/0x%x/%d]", "[slot_list]", (u32)i, - s.dur, s.cxtbl, s.cxtype); + s->dur, s->cxtbl, s->cxtype); else seq_printf(m, ", %02d[%03d/0x%x/%d]", (u32)i, - s.dur, s.cxtbl, s.cxtype); + s->dur, s->cxtbl, s->cxtype); if (i % 6 == 5) seq_puts(m, "\n"); } } -static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_fbtc_cysta_v2(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL; - struct rtw89_btc_fbtc_cysta_cpu pcysta[1]; + struct rtw89_btc_fbtc_cysta_v2 *pcysta_le32 = NULL; union rtw89_btc_fbtc_rxflct r; u8 i, cnt = 0, slot_pair; u16 cycle, c_begin, c_end, store_index; @@ -6207,65 +6415,66 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo; - rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta); + pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo.v2; seq_printf(m, " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", - "[cycle_cnt]", pcysta->cycles, pcysta->bcn_cnt[CXBCN_ALL], - pcysta->bcn_cnt[CXBCN_ALL_OK], - pcysta->bcn_cnt[CXBCN_BT_SLOT], - pcysta->bcn_cnt[CXBCN_BT_OK]); + "[cycle_cnt]", + le16_to_cpu(pcysta_le32->cycles), + le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_ALL]), + le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_ALL_OK]), + le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_BT_SLOT]), + le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_BT_OK])); for (i = 0; i < CXST_MAX; i++) { - if (!pcysta->slot_cnt[i]) + if (!le32_to_cpu(pcysta_le32->slot_cnt[i])) continue; - seq_printf(m, - ", %d:%d", (u32)i, pcysta->slot_cnt[i]); + seq_printf(m, ", %d:%d", (u32)i, + le32_to_cpu(pcysta_le32->slot_cnt[i])); } if (dm->tdma_now.rxflctrl) { - seq_printf(m, - ", leak_rx:%d", pcysta->leakrx_cnt); + seq_printf(m, ", leak_rx:%d", + le32_to_cpu(pcysta_le32->leakrx_cnt)); } - if (pcysta->collision_cnt) { - seq_printf(m, - ", collision:%d", pcysta->collision_cnt); + if (le32_to_cpu(pcysta_le32->collision_cnt)) { + seq_printf(m, ", collision:%d", + le32_to_cpu(pcysta_le32->collision_cnt)); } - if (pcysta->skip_cnt) { - seq_printf(m, - ", skip:%d", pcysta->skip_cnt); + if (le32_to_cpu(pcysta_le32->skip_cnt)) { + seq_printf(m, ", skip:%d", + le32_to_cpu(pcysta_le32->skip_cnt)); } seq_puts(m, "\n"); seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]", "[cycle_time]", - pcysta->tavg_cycle[CXT_WL], - pcysta->tavg_cycle[CXT_BT], - pcysta->tavg_lk / 1000, pcysta->tavg_lk % 1000); - seq_printf(m, - ", max_t[wl:%d/bt:%d/lk:%d.%03d]", - pcysta->tmax_cycle[CXT_WL], - pcysta->tmax_cycle[CXT_BT], - pcysta->tmax_lk / 1000, pcysta->tmax_lk % 1000); - seq_printf(m, - ", maxdiff_t[wl:%d/bt:%d]\n", - pcysta->tmaxdiff_cycle[CXT_WL], - pcysta->tmaxdiff_cycle[CXT_BT]); - - if (pcysta->cycles == 0) + le16_to_cpu(pcysta_le32->tavg_cycle[CXT_WL]), + le16_to_cpu(pcysta_le32->tavg_cycle[CXT_BT]), + le16_to_cpu(pcysta_le32->tavg_lk) / 1000, + le16_to_cpu(pcysta_le32->tavg_lk) % 1000); + seq_printf(m, ", max_t[wl:%d/bt:%d/lk:%d.%03d]", + le16_to_cpu(pcysta_le32->tmax_cycle[CXT_WL]), + le16_to_cpu(pcysta_le32->tmax_cycle[CXT_BT]), + le16_to_cpu(pcysta_le32->tmax_lk) / 1000, + le16_to_cpu(pcysta_le32->tmax_lk) % 1000); + seq_printf(m, ", maxdiff_t[wl:%d/bt:%d]\n", + le16_to_cpu(pcysta_le32->tmaxdiff_cycle[CXT_WL]), + le16_to_cpu(pcysta_le32->tmaxdiff_cycle[CXT_BT])); + + if (le16_to_cpu(pcysta_le32->cycles) == 0) return; /* 1 cycle record 1 wl-slot and 1 bt-slot */ slot_pair = BTC_CYCLE_SLOT_MAX / 2; - if (pcysta->cycles <= slot_pair) + if (le16_to_cpu(pcysta_le32->cycles) <= slot_pair) c_begin = 1; else - c_begin = pcysta->cycles - slot_pair + 1; + c_begin = le16_to_cpu(pcysta_le32->cycles) - slot_pair + 1; - c_end = pcysta->cycles; + c_end = le16_to_cpu(pcysta_le32->cycles); for (cycle = c_begin; cycle <= c_end; cycle++) { cnt++; @@ -6274,13 +6483,13 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 1) seq_printf(m, " %-15s : ->b%02d->w%02d", "[cycle_step]", - pcysta->tslot_cycle[store_index], - pcysta->tslot_cycle[store_index + 1]); + le16_to_cpu(pcysta_le32->tslot_cycle[store_index]), + le16_to_cpu(pcysta_le32->tslot_cycle[store_index + 1])); else seq_printf(m, "->b%02d->w%02d", - pcysta->tslot_cycle[store_index], - pcysta->tslot_cycle[store_index + 1]); + le16_to_cpu(pcysta_le32->tslot_cycle[store_index]), + le16_to_cpu(pcysta_le32->tslot_cycle[store_index + 1])); if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end) seq_puts(m, "\n"); } @@ -6289,41 +6498,43 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) seq_printf(m, " %-15s : a2dp_ept:%d, a2dp_late:%d", "[a2dp_t_sta]", - pcysta->a2dpept, pcysta->a2dpeptto); + le16_to_cpu(pcysta_le32->a2dpept), + le16_to_cpu(pcysta_le32->a2dpeptto)); seq_printf(m, ", avg_t:%d, max_t:%d", - pcysta->tavg_a2dpept, pcysta->tmax_a2dpept); + le16_to_cpu(pcysta_le32->tavg_a2dpept), + le16_to_cpu(pcysta_le32->tmax_a2dpept)); r.val = dm->tdma_now.rxflctrl; if (r.type && r.tgln_n) { seq_printf(m, ", cycle[PSTDMA:%d/TDMA:%d], ", - pcysta->cycles_a2dp[CXT_FLCTRL_ON], - pcysta->cycles_a2dp[CXT_FLCTRL_OFF]); + le16_to_cpu(pcysta_le32->cycles_a2dp[CXT_FLCTRL_ON]), + le16_to_cpu(pcysta_le32->cycles_a2dp[CXT_FLCTRL_OFF])); seq_printf(m, "avg_t[PSTDMA:%d/TDMA:%d], ", - pcysta->tavg_a2dp[CXT_FLCTRL_ON], - pcysta->tavg_a2dp[CXT_FLCTRL_OFF]); + le16_to_cpu(pcysta_le32->tavg_a2dp[CXT_FLCTRL_ON]), + le16_to_cpu(pcysta_le32->tavg_a2dp[CXT_FLCTRL_OFF])); seq_printf(m, "max_t[PSTDMA:%d/TDMA:%d]", - pcysta->tmax_a2dp[CXT_FLCTRL_ON], - pcysta->tmax_a2dp[CXT_FLCTRL_OFF]); + le16_to_cpu(pcysta_le32->tmax_a2dp[CXT_FLCTRL_ON]), + le16_to_cpu(pcysta_le32->tmax_a2dp[CXT_FLCTRL_OFF])); } seq_puts(m, "\n"); } } -static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_fbtc_cysta_v3(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_fbtc_a2dp_trx_stat *a2dp_trx; - struct rtw89_btc_fbtc_cysta_v1 *pcysta; + struct rtw89_btc_fbtc_cysta_v3 *pcysta; struct rtw89_btc_rpt_cmn_info *pcinfo; u8 i, cnt = 0, slot_pair, divide_cnt; u16 cycle, c_begin, c_end, store_index; @@ -6332,7 +6543,7 @@ static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - pcysta = &pfwinfo->rpt_fbtc_cysta.finfo_v1; + pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v3; seq_printf(m, " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", "[cycle_cnt]", @@ -6447,14 +6658,146 @@ static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) } } +static void _show_fbtc_cysta_v4(struct rtw89_dev *rtwdev, struct seq_file *m) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; + struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_fbtc_a2dp_trx_stat_v4 *a2dp_trx; + struct rtw89_btc_fbtc_cysta_v4 *pcysta; + struct rtw89_btc_rpt_cmn_info *pcinfo; + u8 i, cnt = 0, slot_pair, divide_cnt; + u16 cycle, c_begin, c_end, store_index; + + pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo; + if (!pcinfo->valid) + return; + + pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v4; + seq_printf(m, + " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", + "[cycle_cnt]", + le16_to_cpu(pcysta->cycles), + le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]), + le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]), + le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]), + le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK])); + + for (i = 0; i < CXST_MAX; i++) { + if (!le16_to_cpu(pcysta->slot_cnt[i])) + continue; + + seq_printf(m, ", %s:%d", id_to_slot(i), + le16_to_cpu(pcysta->slot_cnt[i])); + } + + if (dm->tdma_now.rxflctrl) + seq_printf(m, ", leak_rx:%d", + le32_to_cpu(pcysta->leak_slot.cnt_rximr)); + + if (pcysta->collision_cnt) + seq_printf(m, ", collision:%d", pcysta->collision_cnt); + + if (le16_to_cpu(pcysta->skip_cnt)) + seq_printf(m, ", skip:%d", + le16_to_cpu(pcysta->skip_cnt)); + + seq_puts(m, "\n"); + + seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]", + "[cycle_time]", + le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]), + le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]), + le16_to_cpu(pcysta->leak_slot.tavg) / 1000, + le16_to_cpu(pcysta->leak_slot.tavg) % 1000); + seq_printf(m, + ", max_t[wl:%d/bt:%d/lk:%d.%03d]", + le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]), + le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]), + le16_to_cpu(pcysta->leak_slot.tmax) / 1000, + le16_to_cpu(pcysta->leak_slot.tmax) % 1000); + seq_printf(m, + ", maxdiff_t[wl:%d/bt:%d]\n", + le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_WL]), + le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_BT])); + + cycle = le16_to_cpu(pcysta->cycles); + if (cycle == 0) + return; + + /* 1 cycle record 1 wl-slot and 1 bt-slot */ + slot_pair = BTC_CYCLE_SLOT_MAX / 2; + + if (cycle <= slot_pair) + c_begin = 1; + else + c_begin = cycle - slot_pair + 1; + + c_end = cycle; + + if (a2dp->exist) + divide_cnt = 3; + else + divide_cnt = BTC_CYCLE_SLOT_MAX / 4; + + for (cycle = c_begin; cycle <= c_end; cycle++) { + cnt++; + store_index = ((cycle - 1) % slot_pair) * 2; + + if (cnt % divide_cnt == 1) { + seq_printf(m, "\n\r %-15s : ", "[cycle_step]"); + } else { + seq_printf(m, "->b%02d", + le16_to_cpu(pcysta->slot_step_time[store_index])); + if (a2dp->exist) { + a2dp_trx = &pcysta->a2dp_trx[store_index]; + seq_printf(m, "(%d/%d/%dM/%d/%d/%d)", + a2dp_trx->empty_cnt, + a2dp_trx->retry_cnt, + a2dp_trx->tx_rate ? 3 : 2, + a2dp_trx->tx_cnt, + a2dp_trx->ack_cnt, + a2dp_trx->nack_cnt); + } + seq_printf(m, "->w%02d", + le16_to_cpu(pcysta->slot_step_time[store_index + 1])); + if (a2dp->exist) { + a2dp_trx = &pcysta->a2dp_trx[store_index + 1]; + seq_printf(m, "(%d/%d/%dM/%d/%d/%d)", + a2dp_trx->empty_cnt, + a2dp_trx->retry_cnt, + a2dp_trx->tx_rate ? 3 : 2, + a2dp_trx->tx_cnt, + a2dp_trx->ack_cnt, + a2dp_trx->nack_cnt); + } + } + if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end) + seq_puts(m, "\n"); + } + + if (a2dp->exist) { + seq_printf(m, "%-15s : a2dp_ept:%d, a2dp_late:%d", + "[a2dp_t_sta]", + le16_to_cpu(pcysta->a2dp_ept.cnt), + le16_to_cpu(pcysta->a2dp_ept.cnt_timeout)); + + seq_printf(m, ", avg_t:%d, max_t:%d", + le16_to_cpu(pcysta->a2dp_ept.tavg), + le16_to_cpu(pcysta->a2dp_ept.tmax)); + + seq_puts(m, "\n"); + } +} + static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo; - struct rtw89_btc_fbtc_cynullsta *ns; - struct rtw89_btc_fbtc_cynullsta_v1 *ns_v1; + union rtw89_btc_fbtc_cynullsta_info *ns; u8 i = 0; if (!btc->dm.tdma_now.rxflctrl) @@ -6464,9 +6807,8 @@ static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - if (chip->chip_id == RTL8852A) { - ns = &pfwinfo->rpt_fbtc_nullsta.finfo; - + ns = &pfwinfo->rpt_fbtc_nullsta.finfo; + if (ver->fcxnullsta == 1) { seq_printf(m, " %-15s : ", "[null_sta]"); for (i = 0; i < 2; i++) { @@ -6475,57 +6817,54 @@ static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m) else seq_printf(m, "null-%d", i); seq_printf(m, "[ok:%d/", - le32_to_cpu(ns->result[i][1])); + le32_to_cpu(ns->v1.result[i][1])); seq_printf(m, "fail:%d/", - le32_to_cpu(ns->result[i][0])); + le32_to_cpu(ns->v1.result[i][0])); seq_printf(m, "on_time:%d/", - le32_to_cpu(ns->result[i][2])); + le32_to_cpu(ns->v1.result[i][2])); seq_printf(m, "retry:%d/", - le32_to_cpu(ns->result[i][3])); + le32_to_cpu(ns->v1.result[i][3])); seq_printf(m, "avg_t:%d.%03d/", - le32_to_cpu(ns->avg_t[i]) / 1000, - le32_to_cpu(ns->avg_t[i]) % 1000); + le32_to_cpu(ns->v1.avg_t[i]) / 1000, + le32_to_cpu(ns->v1.avg_t[i]) % 1000); seq_printf(m, "max_t:%d.%03d]", - le32_to_cpu(ns->max_t[i]) / 1000, - le32_to_cpu(ns->max_t[i]) % 1000); + le32_to_cpu(ns->v1.max_t[i]) / 1000, + le32_to_cpu(ns->v1.max_t[i]) % 1000); } } else { - ns_v1 = &pfwinfo->rpt_fbtc_nullsta.finfo_v1; - seq_printf(m, " %-15s : ", "[null_sta]"); - for (i = 0; i < 2; i++) { if (i != 0) seq_printf(m, ", null-%d", i); else seq_printf(m, "null-%d", i); seq_printf(m, "[Tx:%d/", - le32_to_cpu(ns_v1->result[i][4])); + le32_to_cpu(ns->v2.result[i][4])); seq_printf(m, "[ok:%d/", - le32_to_cpu(ns_v1->result[i][1])); + le32_to_cpu(ns->v2.result[i][1])); seq_printf(m, "fail:%d/", - le32_to_cpu(ns_v1->result[i][0])); + le32_to_cpu(ns->v2.result[i][0])); seq_printf(m, "on_time:%d/", - le32_to_cpu(ns_v1->result[i][2])); + le32_to_cpu(ns->v2.result[i][2])); seq_printf(m, "retry:%d/", - le32_to_cpu(ns_v1->result[i][3])); + le32_to_cpu(ns->v2.result[i][3])); seq_printf(m, "avg_t:%d.%03d/", - le32_to_cpu(ns_v1->avg_t[i]) / 1000, - le32_to_cpu(ns_v1->avg_t[i]) % 1000); + le32_to_cpu(ns->v2.avg_t[i]) / 1000, + le32_to_cpu(ns->v2.avg_t[i]) % 1000); seq_printf(m, "max_t:%d.%03d]", - le32_to_cpu(ns_v1->max_t[i]) / 1000, - le32_to_cpu(ns_v1->max_t[i]) % 1000); + le32_to_cpu(ns->v2.max_t[i]) / 1000, + le32_to_cpu(ns->v2.max_t[i]) % 1000); } } seq_puts(m, "\n"); } -static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_fbtc_step_v2(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_steps *pstep = NULL; + struct rtw89_btc_fbtc_steps_v2 *pstep = NULL; u8 type, val, cnt = 0, state = 0; bool outloop = false; u16 i, diff_t, n_start = 0, n_stop = 0; @@ -6535,7 +6874,7 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - pstep = &pfwinfo->rpt_fbtc_step.finfo; + pstep = &pfwinfo->rpt_fbtc_step.finfo.v2; pos_old = le16_to_cpu(pstep->pos_old); pos_new = le16_to_cpu(pstep->pos_new); @@ -6589,10 +6928,67 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) } while (!outloop); } +static void _show_fbtc_step_v3(struct rtw89_dev *rtwdev, struct seq_file *m) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; + struct rtw89_btc_rpt_cmn_info *pcinfo; + struct rtw89_btc_fbtc_steps_v3 *pstep; + u32 i, n_begin, n_end, array_idx, cnt = 0; + u8 type, val; + u16 diff_t; + + if ((pfwinfo->rpt_en_map & + rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_FW_STEP_INFO)) == 0) + return; + + pcinfo = &pfwinfo->rpt_fbtc_step.cinfo; + if (!pcinfo->valid) + return; + + pstep = &pfwinfo->rpt_fbtc_step.finfo.v3; + if (pcinfo->req_fver != pstep->fver) + return; + + if (le32_to_cpu(pstep->cnt) <= FCXDEF_STEP) + n_begin = 1; + else + n_begin = le32_to_cpu(pstep->cnt) - FCXDEF_STEP + 1; + + n_end = le32_to_cpu(pstep->cnt); + + if (n_begin > n_end) + return; + + /* restore step info by using ring instead of FIFO */ + for (i = n_begin; i <= n_end; i++) { + array_idx = (i - 1) % FCXDEF_STEP; + type = pstep->step[array_idx].type; + val = pstep->step[array_idx].val; + diff_t = le16_to_cpu(pstep->step[array_idx].difft); + + if (type == CXSTEP_NONE || type >= CXSTEP_MAX) + continue; + + if (cnt % 10 == 0) + seq_printf(m, " %-15s : ", "[steps]"); + + seq_printf(m, "-> %s(%02d)", + (type == CXSTEP_SLOT ? + id_to_slot((u32)val) : + id_to_evt((u32)val)), diff_t); + + if (cnt % 10 == 9) + seq_puts(m, "\n"); + + cnt++; + } +} + static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM)) return; @@ -6601,13 +6997,20 @@ static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m) _show_fbtc_tdma(rtwdev, m); _show_fbtc_slots(rtwdev, m); - if (chip->chip_id == RTL8852A) - _show_fbtc_cysta(rtwdev, m); - else - _show_fbtc_cysta_v1(rtwdev, m); + if (ver->fcxcysta == 2) + _show_fbtc_cysta_v2(rtwdev, m); + else if (ver->fcxcysta == 3) + _show_fbtc_cysta_v3(rtwdev, m); + else if (ver->fcxcysta == 4) + _show_fbtc_cysta_v4(rtwdev, m); _show_fbtc_nullsta(rtwdev, m); - _show_fbtc_step(rtwdev, m); + + if (ver->fcxstep == 2) + _show_fbtc_step_v2(rtwdev, m); + else if (ver->fcxstep == 3) + _show_fbtc_step_v3(rtwdev, m); + } static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt_cfg) @@ -6680,10 +7083,7 @@ static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m) /* To avoid I/O if WL LPS or power-off */ if (!wl->status.map.lps && !wl->status.map.rf_off) { - if (chip->chip_id == RTL8852A) - btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev); - else if (chip->chip_id == RTL8852C) - btc->dm.pta_owner = 0; + btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev); _get_gnt(rtwdev, &gnt_cfg); gnt = gnt_cfg.band[0]; @@ -6754,12 +7154,12 @@ static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m) seq_puts(m, "\n"); } -static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_rpt_ctrl *prptctrl = NULL; + struct rtw89_btc_fbtc_rpt_ctrl_v1 *prptctrl = NULL; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_wl_info *wl = &cx->wl; @@ -6774,7 +7174,7 @@ static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m) pcinfo = &pfwinfo->rpt_ctrl.cinfo; if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) { - prptctrl = &pfwinfo->rpt_ctrl.finfo; + prptctrl = &pfwinfo->rpt_ctrl.finfo.v1; seq_printf(m, " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ", @@ -6858,11 +7258,11 @@ static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m) cnt[BTC_NCNT_CUSTOMERIZE]); } -static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_summary_v4(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; - struct rtw89_btc_fbtc_rpt_ctrl_v1 *prptctrl; + struct rtw89_btc_fbtc_rpt_ctrl_v4 *prptctrl; struct rtw89_btc_rpt_cmn_info *pcinfo; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_dm *dm = &btc->dm; @@ -6878,7 +7278,7 @@ static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m) pcinfo = &pfwinfo->rpt_ctrl.cinfo; if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) { - prptctrl = &pfwinfo->rpt_ctrl.finfo_v1; + prptctrl = &pfwinfo->rpt_ctrl.finfo.v4; seq_printf(m, " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ", @@ -6970,11 +7370,127 @@ static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m) cnt[BTC_NCNT_CUSTOMERIZE]); } +static void _show_summary_v5(struct rtw89_dev *rtwdev, struct seq_file *m) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; + struct rtw89_btc_fbtc_rpt_ctrl_v5 *prptctrl; + struct rtw89_btc_rpt_cmn_info *pcinfo; + struct rtw89_btc_cx *cx = &btc->cx; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_wl_info *wl = &cx->wl; + u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify; + u8 i; + + if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY)) + return; + + seq_puts(m, "========== [Statistics] ==========\n"); + + pcinfo = &pfwinfo->rpt_ctrl.cinfo; + if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) { + prptctrl = &pfwinfo->rpt_ctrl.finfo.v5; + + seq_printf(m, + " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d), ", + "[summary]", pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail, + le16_to_cpu(prptctrl->rpt_info.cnt_h2c), + pfwinfo->cnt_c2h, + le16_to_cpu(prptctrl->rpt_info.cnt_c2h), + le16_to_cpu(prptctrl->rpt_info.len_c2h)); + + seq_printf(m, + "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x", + pfwinfo->event[BTF_EVNT_RPT], + le16_to_cpu(prptctrl->rpt_info.cnt), + le32_to_cpu(prptctrl->rpt_info.en)); + + if (dm->error.map.wl_fw_hang) + seq_puts(m, " (WL FW Hang!!)"); + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : send_ok:%d, send_fail:%d, recv:%d, ", + "[mailbox]", + le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok), + le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail), + le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv)); + + seq_printf(m, + "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n", + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty), + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl), + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx), + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack), + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack)); + + seq_printf(m, + " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d]", + "[RFK/LPS]", cx->cnt_wl[BTC_WCNT_RFK_REQ], + cx->cnt_wl[BTC_WCNT_RFK_GO], + cx->cnt_wl[BTC_WCNT_RFK_REJECT], + cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]); + + seq_printf(m, + ", bt_rfk[req:%d]", + le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ])); + + seq_printf(m, + ", AOAC[RF_on:%d/RF_off:%d]", + le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on), + le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off)); + } else { + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d", + "[summary]", pfwinfo->cnt_h2c, + pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h); + } + + if (!pcinfo->valid || pfwinfo->len_mismch || pfwinfo->fver_mismch || + pfwinfo->err[BTFRE_EXCEPTION]) { + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : WL FW rpt error!![rpt_ctrl_valid:%d/len:" + "0x%x/ver:0x%x/ex:%d/lps=%d/rf_off=%d]", + "[ERROR]", pcinfo->valid, pfwinfo->len_mismch, + pfwinfo->fver_mismch, pfwinfo->err[BTFRE_EXCEPTION], + wl->status.map.lps, wl->status.map.rf_off); + } + + for (i = 0; i < BTC_NCNT_NUM; i++) + cnt_sum += dm->cnt_notify[i]; + + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ", + "[notify_cnt]", + cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO], + cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]); + + seq_printf(m, + "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d", + cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE], + cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK], + cnt[BTC_NCNT_WL_STA]); + + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ", + "[notify_cnt]", + cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH], + cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SPECIAL_PACKET]); + + seq_printf(m, + "timer=%d, control=%d, customerize=%d", + cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL], + cnt[BTC_NCNT_CUSTOMERIZE]); +} + void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_fw_suit *fw_suit = &rtwdev->fw.normal; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_bt_info *bt = &cx->bt; @@ -7003,8 +7519,41 @@ void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m) _show_dm_info(rtwdev, m); _show_fw_dm_msg(rtwdev, m); _show_mreg(rtwdev, m); - if (chip->chip_id == RTL8852A) - _show_summary(rtwdev, m); - else + if (ver->fcxbtcrpt == 1) _show_summary_v1(rtwdev, m); + else if (ver->fcxbtcrpt == 4) + _show_summary_v4(rtwdev, m); + else if (ver->fcxbtcrpt == 5) + _show_summary_v5(rtwdev, m); +} + +void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *btc_ver_def; + const struct rtw89_fw_suit *fw_suit; + u32 suit_ver_code; + int i; + + fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_NORMAL); + suit_ver_code = RTW89_FW_SUIT_VER_CODE(fw_suit); + + for (i = 0; i < ARRAY_SIZE(rtw89_btc_ver_defs); i++) { + btc_ver_def = &rtw89_btc_ver_defs[i]; + + if (chip->chip_id != btc_ver_def->chip_id) + continue; + + if (suit_ver_code >= btc_ver_def->fw_ver_code) { + btc->ver = btc_ver_def; + goto out; + } + } + + btc->ver = &rtw89_btc_ver_defs[RTW89_DEFAULT_BTC_VER_IDX]; + +out: + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] use version def[%d] = 0x%08x\n", + (int)(btc->ver - rtw89_btc_ver_defs), btc->ver->fw_ver_code); } diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index ca16afa97ec0..401fb55df82b 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -164,6 +164,7 @@ void rtw89_coex_rfk_chk_work(struct work_struct *work); void rtw89_coex_power_on(struct rtw89_dev *rtwdev); void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type); void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type); +void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev); static inline u8 rtw89_btc_phymap(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 931aff8b5dc9..4cf4a81ed4f7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -498,7 +498,8 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); u16 lowest_rate; - if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE || vif->p2p) + if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE || + (vif && vif->p2p)) lowest_rate = RTW89_HW_RATE_OFDM6; else if (chan->band_type == RTW89_BAND_2G) lowest_rate = RTW89_HW_RATE_CCK1; @@ -511,6 +512,21 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev, return __ffs(vif->bss_conf.basic_rates) + lowest_rate; } +static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct ieee80211_vif *vif = tx_req->vif; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct ieee80211_sta *sta = tx_req->sta; + struct rtw89_sta *rtwsta; + + if (!sta) + return rtwvif->mac_id; + + rtwsta = (struct rtw89_sta *)sta->drv_priv; + return rtwsta->mac_id; +} + static void rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) @@ -527,6 +543,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, desc_info->qsel = qsel; desc_info->ch_dma = ch_dma; desc_info->port = desc_info->hiq ? rtwvif->port : 0; + desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->hw_ssn_sel = RTW89_MGMT_HW_SSN_SEL; desc_info->hw_seq_mode = RTW89_MGMT_HW_SEQ_MODE; @@ -669,27 +686,14 @@ desc_bk: desc_info->bk = true; } -static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev, - struct rtw89_core_tx_request *tx_req) -{ - struct ieee80211_vif *vif = tx_req->vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_sta *rtwsta; - - if (!sta) - return rtwvif->mac_id; - - rtwsta = (struct rtw89_sta *)sta->drv_priv; - return rtwsta->mac_id; -} - static void rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { struct ieee80211_vif *vif = tx_req->vif; + struct ieee80211_sta *sta = tx_req->sta; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; @@ -707,6 +711,7 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, desc_info->qsel = qsel; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->port = desc_info->hiq ? rtwvif->port : 0; + desc_info->er_cap = rtwsta ? rtwsta->er_cap : false; /* enable wd_info for AMPDU */ desc_info->en_wd_info = true; @@ -1006,7 +1011,9 @@ static __le32 rtw89_build_txwd_info0(struct rtw89_tx_desc_info *desc_info) static __le32 rtw89_build_txwd_info0_v1(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(RTW89_TXWD_INFO0_DISDATAFB, desc_info->dis_data_fb) | - FIELD_PREP(RTW89_TXWD_INFO0_MULTIPORT_ID, desc_info->port); + FIELD_PREP(RTW89_TXWD_INFO0_MULTIPORT_ID, desc_info->port) | + FIELD_PREP(RTW89_TXWD_INFO0_DATA_ER, desc_info->er_cap) | + FIELD_PREP(RTW89_TXWD_INFO0_DATA_BW_ER, 0); return cpu_to_le32(dword); } @@ -2585,6 +2592,12 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, rtw89_mac_bf_monitor_calc(rtwdev, sta, false); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + + if (bss_conf->he_support && + !(bss_conf->he_oper.params & IEEE80211_HE_OPERATION_ER_SU_DISABLE)) + rtwsta->er_cap = true; + rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, BTC_ROLE_MSTS_STA_CONN_END); rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template); @@ -3124,6 +3137,8 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_DELAYED_WORK(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work); INIT_DELAYED_WORK(&rtwdev->forbid_ba_work, rtw89_forbid_ba_work); rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!rtwdev->txq_wq) + return -ENOMEM; spin_lock_init(&rtwdev->ba_lock); spin_lock_init(&rtwdev->rpwm_lock); mutex_init(&rtwdev->mutex); @@ -3149,6 +3164,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) ret = rtw89_load_firmware(rtwdev); if (ret) { rtw89_warn(rtwdev, "no firmware loaded\n"); + destroy_workqueue(rtwdev->txq_wq); return ret; } rtw89_ser_init(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2badb96d2ae3..39c5a003e36c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -816,6 +816,7 @@ struct rtw89_tx_desc_info { #define RTW89_MGMT_HW_SEQ_MODE 1 bool hiq; u8 port; + bool er_cap; }; struct rtw89_core_tx_request { @@ -1263,6 +1264,7 @@ union rtw89_btc_bt_state_map { #define BTC_BT_RSSI_THMAX 4 #define BTC_BT_AFH_GROUP 12 +#define BTC_BT_AFH_LE_GROUP 5 struct rtw89_btc_bt_link_info { struct rtw89_btc_u8_sta_chg profile_cnt; @@ -1278,6 +1280,7 @@ struct rtw89_btc_bt_link_info { u8 golden_rx_shift[BTC_PROFILE_MAX]; u8 rssi_state[BTC_BT_RSSI_THMAX]; u8 afh_map[BTC_BT_AFH_GROUP]; + u8 afh_map_le[BTC_BT_AFH_LE_GROUP]; u32 role_sw: 1; u32 slave_role: 1; @@ -1437,7 +1440,7 @@ struct rtw89_btc_cx { }; struct rtw89_btc_fbtc_tdma { - u8 type; /* chip_info::fcxtdma_ver */ + u8 type; /* btc_ver::fcxtdma */ u8 rxflctrl; u8 txpause; u8 wtgle_n; @@ -1447,13 +1450,18 @@ struct rtw89_btc_fbtc_tdma { u8 option_ctrl; } __packed; -struct rtw89_btc_fbtc_tdma_v1 { - u8 fver; /* chip_info::fcxtdma_ver */ +struct rtw89_btc_fbtc_tdma_v3 { + u8 fver; /* btc_ver::fcxtdma */ u8 rsvd; __le16 rsvd1; struct rtw89_btc_fbtc_tdma tdma; } __packed; +union rtw89_btc_fbtc_tdma_le32 { + struct rtw89_btc_fbtc_tdma v1; + struct rtw89_btc_fbtc_tdma_v3 v3; +}; + #define CXMREG_MAX 30 #define FCXMAX_STEP 255 /*STEP trace record cnt, Max:65535, default:255*/ #define BTC_CYCLE_SLOT_MAX 48 /* must be even number, non-zero */ @@ -1472,8 +1480,8 @@ enum rtw89_btc_bt_sta_counter { BTC_BCNT_STA_MAX }; -struct rtw89_btc_fbtc_rpt_ctrl { - u16 fver; /* chip_info::fcxbtcrpt_ver */ +struct rtw89_btc_fbtc_rpt_ctrl_v1 { + u16 fver; /* btc_ver::fcxbtcrpt */ u16 rpt_cnt; /* tmr counters */ u32 wl_fw_coex_ver; /* match which driver's coex version */ u32 wl_fw_cx_offload; @@ -1504,6 +1512,20 @@ struct rtw89_btc_fbtc_rpt_ctrl_info { __le32 cnt_aoac_rf_off; /* rf-off counter for aoac switch notify */ } __packed; +struct rtw89_btc_fbtc_rpt_ctrl_info_v5 { + __le32 cx_ver; /* match which driver's coex version */ + __le32 fw_ver; + __le32 en; /* report map */ + + __le16 cnt; /* fw report counter */ + __le16 cnt_c2h; /* fw send c2h counter */ + __le16 cnt_h2c; /* fw recv h2c counter */ + __le16 len_c2h; /* The total length of the last C2H */ + + __le16 cnt_aoac_rf_on; /* rf-on counter for aoac switch notify */ + __le16 cnt_aoac_rf_off; /* rf-off counter for aoac switch notify */ +} __packed; + struct rtw89_btc_fbtc_rpt_ctrl_wl_fw_info { __le32 cx_ver; /* match which driver's coex version */ __le32 cx_offload; @@ -1525,7 +1547,7 @@ struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox { struct rtw89_btc_fbtc_rpt_ctrl_a2dp_empty a2dp; } __packed; -struct rtw89_btc_fbtc_rpt_ctrl_v1 { +struct rtw89_btc_fbtc_rpt_ctrl_v4 { u8 fver; u8 rsvd; __le16 rsvd1; @@ -1536,6 +1558,24 @@ struct rtw89_btc_fbtc_rpt_ctrl_v1 { struct rtw89_mac_ax_gnt gnt_val[RTW89_PHY_MAX]; } __packed; +struct rtw89_btc_fbtc_rpt_ctrl_v5 { + u8 fver; + u8 rsvd; + __le16 rsvd1; + + u8 gnt_val[RTW89_PHY_MAX][4]; + __le16 bt_cnt[BTC_BCNT_STA_MAX]; + + struct rtw89_btc_fbtc_rpt_ctrl_info_v5 rpt_info; + struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox bt_mbx_info; +} __packed; + +union rtw89_btc_fbtc_rpt_ctrl_ver_info { + struct rtw89_btc_fbtc_rpt_ctrl_v1 v1; + struct rtw89_btc_fbtc_rpt_ctrl_v4 v4; + struct rtw89_btc_fbtc_rpt_ctrl_v5 v5; +}; + enum rtw89_fbtc_ext_ctrl_type { CXECTL_OFF = 0x0, /* tdma off */ CXECTL_B2 = 0x1, /* allow B2 (beacon-early) */ @@ -1571,6 +1611,36 @@ enum rtw89_btc_cxst_state { CXST_MAX = 0x12, }; +enum rtw89_btc_cxevnt { + CXEVNT_TDMA_ENTRY = 0x0, + CXEVNT_WL_TMR, + CXEVNT_B1_TMR, + CXEVNT_B2_TMR, + CXEVNT_B3_TMR, + CXEVNT_B4_TMR, + CXEVNT_W2B_TMR, + CXEVNT_B2W_TMR, + CXEVNT_BCN_EARLY, + CXEVNT_A2DP_EMPTY, + CXEVNT_LK_END, + CXEVNT_RX_ISR, + CXEVNT_RX_FC0, + CXEVNT_RX_FC1, + CXEVNT_BT_RELINK, + CXEVNT_BT_RETRY, + CXEVNT_E2G, + CXEVNT_E5G, + CXEVNT_EBT, + CXEVNT_ENULL, + CXEVNT_DRV_WLK, + CXEVNT_BCN_OK, + CXEVNT_BT_CHANGE, + CXEVNT_EBT_EXTEND, + CXEVNT_E2G_NULL1, + CXEVNT_B1FDD_TMR, + CXEVNT_MAX +}; + enum { CXBCN_ALL = 0x0, CXBCN_ALL_OK, @@ -1604,9 +1674,14 @@ enum { /* STEP TYPE */ CXSTEP_MAX, }; +enum rtw89_btc_afh_map_type { /*AFH MAP TYPE */ + RPT_BT_AFH_SEQ_LEGACY = 0x10, + RPT_BT_AFH_SEQ_LE = 0x20 +}; + #define BTC_DBG_MAX1 32 struct rtw89_btc_fbtc_gpio_dbg { - u8 fver; /* chip_info::fcxgpiodbg_ver */ + u8 fver; /* btc_ver::fcxgpiodbg */ u8 rsvd; u16 rsvd2; u32 en_map; /* which debug signal (see btc_wl_gpio_debug) is enable */ @@ -1615,7 +1690,7 @@ struct rtw89_btc_fbtc_gpio_dbg { } __packed; struct rtw89_btc_fbtc_mreg_val { - u8 fver; /* chip_info::fcxmreg_ver */ + u8 fver; /* btc_ver::fcxmreg */ u8 reg_num; __le16 rsvd; __le32 mreg_val[CXMREG_MAX]; @@ -1638,7 +1713,7 @@ struct rtw89_btc_fbtc_slot { } __packed; struct rtw89_btc_fbtc_slots { - u8 fver; /* chip_info::fcxslots_ver */ + u8 fver; /* btc_ver::fcxslots */ u8 tbl_num; __le16 rsvd; __le32 update_map; @@ -1651,8 +1726,8 @@ struct rtw89_btc_fbtc_step { __le16 difft; } __packed; -struct rtw89_btc_fbtc_steps { - u8 fver; /* chip_info::fcxstep_ver */ +struct rtw89_btc_fbtc_steps_v2 { + u8 fver; /* btc_ver::fcxstep */ u8 rsvd; __le16 cnt; __le16 pos_old; @@ -1660,7 +1735,7 @@ struct rtw89_btc_fbtc_steps { struct rtw89_btc_fbtc_step step[FCXMAX_STEP]; } __packed; -struct rtw89_btc_fbtc_steps_v1 { +struct rtw89_btc_fbtc_steps_v3 { u8 fver; u8 en; __le16 rsvd; @@ -1668,8 +1743,13 @@ struct rtw89_btc_fbtc_steps_v1 { struct rtw89_btc_fbtc_step step[FCXMAX_STEP]; } __packed; -struct rtw89_btc_fbtc_cysta { /* statistics for cycles */ - u8 fver; /* chip_info::fcxcysta_ver */ +union rtw89_btc_fbtc_steps_info { + struct rtw89_btc_fbtc_steps_v2 v2; + struct rtw89_btc_fbtc_steps_v3 v3; +}; + +struct rtw89_btc_fbtc_cysta_v2 { /* statistics for cycles */ + u8 fver; /* btc_ver::fcxcysta */ u8 rsvd; __le16 cycles; /* total cycle number */ __le16 cycles_a2dp[CXT_FLCTRL_MAX]; @@ -1717,6 +1797,17 @@ struct rtw89_btc_fbtc_a2dp_trx_stat { u8 rsvd2; } __packed; +struct rtw89_btc_fbtc_a2dp_trx_stat_v4 { + u8 empty_cnt; + u8 retry_cnt; + u8 tx_rate; + u8 tx_cnt; + u8 ack_cnt; + u8 nack_cnt; + u8 no_empty_cnt; + u8 rsvd; +} __packed; + struct rtw89_btc_fbtc_cycle_a2dp_empty_info { __le16 cnt; /* a2dp empty cnt */ __le16 cnt_timeout; /* a2dp empty timeout cnt*/ @@ -1730,7 +1821,35 @@ struct rtw89_btc_fbtc_cycle_leak_info { __le16 tmax; /* max leak-slot time */ } __packed; -struct rtw89_btc_fbtc_cysta_v1 { /* statistics for cycles */ +#define RTW89_BTC_FDDT_PHASE_CYCLE GENMASK(9, 0) +#define RTW89_BTC_FDDT_TRAIN_STEP GENMASK(15, 10) + +struct rtw89_btc_fbtc_cycle_fddt_info { + __le16 train_cycle; + __le16 tp; + + s8 tx_power; /* absolute Tx power (dBm), 0xff-> no BTC control */ + s8 bt_tx_power; /* decrease Tx power (dB) */ + s8 bt_rx_gain; /* LNA constrain level */ + u8 no_empty_cnt; + + u8 rssi; /* [7:4] -> bt_rssi_level, [3:0]-> wl_rssi_level */ + u8 cn; /* condition_num */ + u8 train_status; /* [7:4]-> train-state, [3:0]-> train-phase */ + u8 train_result; /* refer to enum btc_fddt_check_map */ +} __packed; + +#define RTW89_BTC_FDDT_CELL_TRAIN_STATE GENMASK(3, 0) +#define RTW89_BTC_FDDT_CELL_TRAIN_PHASE GENMASK(7, 4) + +struct rtw89_btc_fbtc_fddt_cell_status { + s8 wl_tx_pwr; + s8 bt_tx_pwr; + s8 bt_rx_gain; + u8 state_phase; /* [0:3] train state, [4:7] train phase */ +} __packed; + +struct rtw89_btc_fbtc_cysta_v3 { /* statistics for cycles */ u8 fver; u8 rsvd; __le16 cycles; /* total cycle number */ @@ -1748,8 +1867,41 @@ struct rtw89_btc_fbtc_cysta_v1 { /* statistics for cycles */ __le32 except_map; } __packed; -struct rtw89_btc_fbtc_cynullsta { /* cycle null statistics */ - u8 fver; /* chip_info::fcxnullsta_ver */ +#define FDD_TRAIN_WL_DIRECTION 2 +#define FDD_TRAIN_WL_RSSI_LEVEL 5 +#define FDD_TRAIN_BT_RSSI_LEVEL 5 + +struct rtw89_btc_fbtc_cysta_v4 { /* statistics for cycles */ + u8 fver; + u8 rsvd; + u8 collision_cnt; /* counter for event/timer occur at the same time */ + u8 except_cnt; + + __le16 skip_cnt; + __le16 cycles; /* total cycle number */ + + __le16 slot_step_time[BTC_CYCLE_SLOT_MAX]; /* record the wl/bt slot time */ + __le16 slot_cnt[CXST_MAX]; /* slot count */ + __le16 bcn_cnt[CXBCN_MAX]; + struct rtw89_btc_fbtc_cycle_time_info cycle_time; + struct rtw89_btc_fbtc_cycle_leak_info leak_slot; + struct rtw89_btc_fbtc_cycle_a2dp_empty_info a2dp_ept; + struct rtw89_btc_fbtc_a2dp_trx_stat_v4 a2dp_trx[BTC_CYCLE_SLOT_MAX]; + struct rtw89_btc_fbtc_cycle_fddt_info fddt_trx[BTC_CYCLE_SLOT_MAX]; + struct rtw89_btc_fbtc_fddt_cell_status fddt_cells[FDD_TRAIN_WL_DIRECTION] + [FDD_TRAIN_WL_RSSI_LEVEL] + [FDD_TRAIN_BT_RSSI_LEVEL]; + __le32 except_map; +} __packed; + +union rtw89_btc_fbtc_cysta_info { + struct rtw89_btc_fbtc_cysta_v2 v2; + struct rtw89_btc_fbtc_cysta_v3 v3; + struct rtw89_btc_fbtc_cysta_v4 v4; +}; + +struct rtw89_btc_fbtc_cynullsta_v1 { /* cycle null statistics */ + u8 fver; /* btc_ver::fcxnullsta */ u8 rsvd; __le16 rsvd2; __le32 max_t[2]; /* max_t for 0:null0/1:null1 */ @@ -1757,8 +1909,8 @@ struct rtw89_btc_fbtc_cynullsta { /* cycle null statistics */ __le32 result[2][4]; /* 0:fail, 1:ok, 2:on_time, 3:retry */ } __packed; -struct rtw89_btc_fbtc_cynullsta_v1 { /* cycle null statistics */ - u8 fver; /* chip_info::fcxnullsta_ver */ +struct rtw89_btc_fbtc_cynullsta_v2 { /* cycle null statistics */ + u8 fver; /* btc_ver::fcxnullsta */ u8 rsvd; __le16 rsvd2; __le32 max_t[2]; /* max_t for 0:null0/1:null1 */ @@ -1766,8 +1918,13 @@ struct rtw89_btc_fbtc_cynullsta_v1 { /* cycle null statistics */ __le32 result[2][5]; /* 0:fail, 1:ok, 2:on_time, 3:retry, 4:tx */ } __packed; +union rtw89_btc_fbtc_cynullsta_info { + struct rtw89_btc_fbtc_cynullsta_v1 v1; /* info from fw */ + struct rtw89_btc_fbtc_cynullsta_v2 v2; +}; + struct rtw89_btc_fbtc_btver { - u8 fver; /* chip_info::fcxbtver_ver */ + u8 fver; /* btc_ver::fcxbtver */ u8 rsvd; __le16 rsvd2; __le32 coex_ver; /*bit[15:8]->shared, bit[7:0]->non-shared */ @@ -1776,14 +1933,14 @@ struct rtw89_btc_fbtc_btver { } __packed; struct rtw89_btc_fbtc_btscan { - u8 fver; /* chip_info::fcxbtscan_ver */ + u8 fver; /* btc_ver::fcxbtscan */ u8 rsvd; __le16 rsvd2; u8 scan[6]; } __packed; struct rtw89_btc_fbtc_btafh { - u8 fver; /* chip_info::fcxbtafh_ver */ + u8 fver; /* btc_ver::fcxbtafh */ u8 rsvd; __le16 rsvd2; u8 afh_l[4]; /*bit0:2402, bit1: 2403.... bit31:2433 */ @@ -1791,8 +1948,20 @@ struct rtw89_btc_fbtc_btafh { u8 afh_h[4]; /*bit0:2466, bit1:2467......bit14:2480 */ } __packed; +struct rtw89_btc_fbtc_btafh_v2 { + u8 fver; /* btc_ver::fcxbtafh */ + u8 rsvd; + u8 rsvd2; + u8 map_type; + u8 afh_l[4]; + u8 afh_m[4]; + u8 afh_h[4]; + u8 afh_le_a[4]; + u8 afh_le_b[4]; +} __packed; + struct rtw89_btc_fbtc_btdevinfo { - u8 fver; /* chip_info::fcxbtdevinfo_ver */ + u8 fver; /* btc_ver::fcxbtdevinfo */ u8 rsvd; __le16 vendor_id; __le32 dev_name; /* only 24 bits valid */ @@ -1911,20 +2080,19 @@ struct rtw89_btc_rpt_cmn_info { u8 valid; } __packed; +union rtw89_btc_fbtc_btafh_info { + struct rtw89_btc_fbtc_btafh v1; + struct rtw89_btc_fbtc_btafh_v2 v2; +}; + struct rtw89_btc_report_ctrl_state { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_rpt_ctrl finfo; /* info from fw for 52A*/ - struct rtw89_btc_fbtc_rpt_ctrl_v1 finfo_v1; /* info from fw for 52C*/ - }; + union rtw89_btc_fbtc_rpt_ctrl_ver_info finfo; }; struct rtw89_btc_rpt_fbtc_tdma { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_tdma finfo; /* info from fw */ - struct rtw89_btc_fbtc_tdma_v1 finfo_v1; /* info from fw for 52C*/ - }; + union rtw89_btc_fbtc_tdma_le32 finfo; }; struct rtw89_btc_rpt_fbtc_slots { @@ -1934,26 +2102,17 @@ struct rtw89_btc_rpt_fbtc_slots { struct rtw89_btc_rpt_fbtc_cysta { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_cysta finfo; /* info from fw for 52A*/ - struct rtw89_btc_fbtc_cysta_v1 finfo_v1; /* info from fw for 52C*/ - }; + union rtw89_btc_fbtc_cysta_info finfo; }; struct rtw89_btc_rpt_fbtc_step { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_steps finfo; /* info from fw */ - struct rtw89_btc_fbtc_steps_v1 finfo_v1; /* info from fw */ - }; + union rtw89_btc_fbtc_steps_info finfo; /* info from fw */ }; struct rtw89_btc_rpt_fbtc_nullsta { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_cynullsta finfo; /* info from fw */ - struct rtw89_btc_fbtc_cynullsta_v1 finfo_v1; /* info from fw */ - }; + union rtw89_btc_fbtc_cynullsta_info finfo; }; struct rtw89_btc_rpt_fbtc_mreg { @@ -1978,7 +2137,7 @@ struct rtw89_btc_rpt_fbtc_btscan { struct rtw89_btc_rpt_fbtc_btafh { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - struct rtw89_btc_fbtc_btafh finfo; /* info from fw */ + union rtw89_btc_fbtc_btafh_info finfo; }; struct rtw89_btc_rpt_fbtc_btdev { @@ -2018,9 +2177,35 @@ struct rtw89_btc_btf_fwinfo { struct rtw89_btc_rpt_fbtc_btdev rpt_fbtc_btdev; }; +struct rtw89_btc_ver { + enum rtw89_core_chip_id chip_id; + u32 fw_ver_code; + + u8 fcxbtcrpt; + u8 fcxtdma; + u8 fcxslots; + u8 fcxcysta; + u8 fcxstep; + u8 fcxnullsta; + u8 fcxmreg; + u8 fcxgpiodbg; + u8 fcxbtver; + u8 fcxbtscan; + u8 fcxbtafh; + u8 fcxbtdevinfo; + u8 fwlrole; + u8 frptmap; + u8 fcxctrl; + + u16 info_buf; + u8 max_role_num; +}; + #define RTW89_BTC_POLICY_MAXLEN 512 struct rtw89_btc { + const struct rtw89_btc_ver *ver; + struct rtw89_btc_cx cx; struct rtw89_btc_dm dm; struct rtw89_btc_ctrl ctrl; @@ -2194,6 +2379,7 @@ struct rtw89_sec_cam_entry { struct rtw89_sta { u8 mac_id; bool disassoc; + bool er_cap; struct rtw89_dev *rtwdev; struct rtw89_vif *rtwvif; struct rtw89_ra_info ra; @@ -2728,20 +2914,6 @@ struct rtw89_chip_info { u8 btcx_desired; u8 scbd; u8 mailbox; - u16 btc_fwinfo_buf; - - u8 fcxbtcrpt_ver; - u8 fcxtdma_ver; - u8 fcxslots_ver; - u8 fcxcysta_ver; - u8 fcxstep_ver; - u8 fcxnullsta_ver; - u8 fcxmreg_ver; - u8 fcxgpiodbg_ver; - u8 fcxbtver_ver; - u8 fcxbtscan_ver; - u8 fcxbtafh_ver; - u8 fcxbtdevinfo_ver; u8 afh_guard_ch; const u8 *wl_rssi_thres; @@ -2771,6 +2943,7 @@ struct rtw89_chip_info { u8 dcfo_comp_sft; const struct rtw89_imr_info *imr_info; const struct rtw89_rrsr_cfgs *rrsr_cfgs; + u32 bss_clr_map_reg; u32 dma_ch_mask; const struct wiphy_wowlan_support *wowlan_stub; }; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index de1f23779fc6..85c7172e931b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -91,6 +91,7 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, const u8 *fwdynhdr; const u8 *bin; u32 base_hdr_len; + u32 mssc_len = 0; u32 i; if (!info) @@ -120,6 +121,14 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, fw += RTW89_FW_HDR_SIZE; section_info = info->section_info; for (i = 0; i < info->section_num; i++) { + section_info->type = GET_FWSECTION_HDR_SECTIONTYPE(fw); + if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { + section_info->mssc = GET_FWSECTION_HDR_MSSC(fw); + mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; + } else { + section_info->mssc = 0; + } + section_info->len = GET_FWSECTION_HDR_SEC_SIZE(fw); if (GET_FWSECTION_HDR_CHECKSUM(fw)) section_info->len += FWDL_SECTION_CHKSUM_LEN; @@ -132,7 +141,7 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, section_info++; } - if (fw_end != bin) { + if (fw_end != bin + mssc_len) { rtw89_err(rtwdev, "[ERR]fw bin size\n"); return -EINVAL; } @@ -343,6 +352,8 @@ int rtw89_fw_recognize(struct rtw89_dev *rtwdev) rtw89_fw_recognize_features(rtwdev); + rtw89_coex_recognize_ver(rtwdev); + return 0; } @@ -1807,33 +1818,36 @@ fail: #define PORT_DATA_OFFSET 4 #define H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN 12 -#define H2C_LEN_CXDRVINFO_ROLE (4 + 12 * RTW89_PORT_NUM + H2C_LEN_CXDRVHDR) -#define H2C_LEN_CXDRVINFO_ROLE_V1 (4 + 16 * RTW89_PORT_NUM + \ - H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + \ - H2C_LEN_CXDRVHDR) +#define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \ + (4 + 12 * (max_role_num) + H2C_LEN_CXDRVHDR) + int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info *role_info = &wl->role_info; struct rtw89_btc_wl_role_info_bpos *bpos = &role_info->role_map.role; struct rtw89_btc_wl_active_role *active = role_info->active_role; struct sk_buff *skb; + u32 len; u8 offset = 0; u8 *cmd; int ret; int i; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_ROLE); + len = H2C_LEN_CXDRVINFO_ROLE_SIZE(ver->max_role_num); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n"); return -ENOMEM; } - skb_put(skb, H2C_LEN_CXDRVINFO_ROLE); + skb_put(skb, len); cmd = skb->data; RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); - RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_ROLE - H2C_LEN_CXDRVHDR); + RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, role_info->link_mode); @@ -1870,7 +1884,7 @@ int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev) rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, BTFC_SET, SET_DRV_INFO, 0, 0, - H2C_LEN_CXDRVINFO_ROLE); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -1885,28 +1899,35 @@ fail: return ret; } +#define H2C_LEN_CXDRVINFO_ROLE_SIZE_V1(max_role_num) \ + (4 + 16 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR) + int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info_v1 *role_info = &wl->role_info_v1; struct rtw89_btc_wl_role_info_bpos *bpos = &role_info->role_map.role; struct rtw89_btc_wl_active_role_v1 *active = role_info->active_role_v1; struct sk_buff *skb; + u32 len; u8 *cmd, offset; int ret; int i; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_ROLE_V1); + len = H2C_LEN_CXDRVINFO_ROLE_SIZE_V1(ver->max_role_num); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n"); return -ENOMEM; } - skb_put(skb, H2C_LEN_CXDRVINFO_ROLE_V1); + skb_put(skb, len); cmd = skb->data; RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); - RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_ROLE_V1 - H2C_LEN_CXDRVHDR); + RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, role_info->link_mode); @@ -1942,7 +1963,7 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) RTW89_SET_FWCMD_CXROLE_ACT_NOA_DUR(cmd, active->noa_duration, i, offset); } - offset = H2C_LEN_CXDRVINFO_ROLE_V1 - H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN; + offset = len - H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN; RTW89_SET_FWCMD_CXROLE_MROLE_TYPE(cmd, role_info->mrole_type, offset); RTW89_SET_FWCMD_CXROLE_MROLE_NOA(cmd, role_info->mrole_noa_duration, offset); RTW89_SET_FWCMD_CXROLE_DBCC_EN(cmd, role_info->dbcc_en, offset); @@ -1953,7 +1974,7 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, BTFC_SET, SET_DRV_INFO, 0, 0, - H2C_LEN_CXDRVINFO_ROLE_V1); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -1971,8 +1992,8 @@ fail: #define H2C_LEN_CXDRVINFO_CTRL (4 + H2C_LEN_CXDRVHDR) int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_ctrl *ctrl = &btc->ctrl; struct sk_buff *skb; u8 *cmd; @@ -1992,7 +2013,7 @@ int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) RTW89_SET_FWCMD_CXCTRL_MANUAL(cmd, ctrl->manual); RTW89_SET_FWCMD_CXCTRL_IGNORE_BT(cmd, ctrl->igno_bt); RTW89_SET_FWCMD_CXCTRL_ALWAYS_FREERUN(cmd, ctrl->always_freerun); - if (chip->chip_id == RTL8852A) + if (ver->fcxctrl == 0) RTW89_SET_FWCMD_CXCTRL_TRACE_STEP(cmd, ctrl->trace_step); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -2665,8 +2686,10 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev, list_add_tail(&info->list, &scan_info->pkt_list[band]); ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new); - if (ret) + if (ret) { + kfree_skb(new); goto out; + } kfree_skb(new); } @@ -2738,7 +2761,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, if (ssid_num == 1 && req->ssids[0].ssid_len == 0) { ch_info->tx_pkt = false; if (!req->duration_mandatory) - ch_info->period -= RTW89_DWELL_TIME; + ch_info->period -= RTW89_DWELL_TIME_6G; } } @@ -2791,7 +2814,8 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, if (req->duration_mandatory) ch_info->period = req->duration; else if (channel->band == NL80211_BAND_6GHZ) - ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME; + ch_info->period = RTW89_CHANNEL_TIME_6G + + RTW89_DWELL_TIME_6G; else ch_info->period = RTW89_CHANNEL_TIME; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 4d2f9ea9e002..3ce59ac48f43 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -171,6 +171,8 @@ struct rtw89_fw_hdr_section_info { const u8 *addr; u32 len; u32 dladdr; + u32 mssc; + u8 type; }; struct rtw89_fw_bin_info { @@ -203,6 +205,7 @@ struct rtw89_h2creg_sch_tx_en { #define RTW89_DFS_CHAN_TIME 105 #define RTW89_OFF_CHAN_TIME 100 #define RTW89_DWELL_TIME 20 +#define RTW89_DWELL_TIME_6G 10 #define RTW89_SCAN_WIDTH 0 #define RTW89_SCANOFLD_MAX_SSID 8 #define RTW89_SCANOFLD_MAX_IE_LEN 512 @@ -480,14 +483,21 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) #define FW_EDCA_PARAM_CWMIN_MSK GENMASK(11, 8) #define FW_EDCA_PARAM_AIFS_MSK GENMASK(7, 0) +#define FWDL_SECURITY_SECTION_TYPE 9 +#define FWDL_SECURITY_SIGLEN 512 + +#define GET_FWSECTION_HDR_DL_ADDR(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr)), GENMASK(31, 0)) +#define GET_FWSECTION_HDR_SECTIONTYPE(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(27, 24)) #define GET_FWSECTION_HDR_SEC_SIZE(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 0)) #define GET_FWSECTION_HDR_CHECKSUM(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(28)) #define GET_FWSECTION_HDR_REDL(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(29)) -#define GET_FWSECTION_HDR_DL_ADDR(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr)), GENMASK(31, 0)) +#define GET_FWSECTION_HDR_MSSC(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 2), GENMASK(31, 0)) #define GET_FW_HDR_MAJOR_VERSION(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(7, 0)) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index cf9a0a3120a7..5ab0590485e0 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4865,9 +4865,16 @@ EXPORT_SYMBOL(rtw89_mac_cfg_ctrl_path_v1); bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev) { - u8 val = rtw89_read8(rtwdev, R_AX_SYS_SDIO_CTRL + 3); + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 val = 0; + + if (chip->chip_id == RTL8852C) + return false; + else if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B) + val = rtw89_read8_mask(rtwdev, R_AX_SYS_SDIO_CTRL + 3, + B_AX_LTE_MUX_CTRL_PATH >> 24); - return FIELD_GET(B_AX_LTE_MUX_CTRL_PATH >> 24, val); + return !!val; } u16 rtw89_mac_get_plt_cnt(struct rtw89_dev *rtwdev, u8 band) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 1c4500ba777c..0ea734c81b4f 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1384,7 +1384,7 @@ static int rtw89_pci_ops_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx return 0; } -static const struct rtw89_pci_bd_ram bd_ram_table[RTW89_TXCH_NUM] = { +const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM] = { [RTW89_TXCH_ACH0] = {.start_idx = 0, .max_num = 5, .min_num = 2}, [RTW89_TXCH_ACH1] = {.start_idx = 5, .max_num = 5, .min_num = 2}, [RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2}, @@ -1399,11 +1399,24 @@ static const struct rtw89_pci_bd_ram bd_ram_table[RTW89_TXCH_NUM] = { [RTW89_TXCH_CH11] = {.start_idx = 55, .max_num = 5, .min_num = 1}, [RTW89_TXCH_CH12] = {.start_idx = 60, .max_num = 4, .min_num = 1}, }; +EXPORT_SYMBOL(rtw89_bd_ram_table_dual); + +const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM] = { + [RTW89_TXCH_ACH0] = {.start_idx = 0, .max_num = 5, .min_num = 2}, + [RTW89_TXCH_ACH1] = {.start_idx = 5, .max_num = 5, .min_num = 2}, + [RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2}, + [RTW89_TXCH_ACH3] = {.start_idx = 15, .max_num = 5, .min_num = 2}, + [RTW89_TXCH_CH8] = {.start_idx = 20, .max_num = 4, .min_num = 1}, + [RTW89_TXCH_CH9] = {.start_idx = 24, .max_num = 4, .min_num = 1}, + [RTW89_TXCH_CH12] = {.start_idx = 28, .max_num = 4, .min_num = 1}, +}; +EXPORT_SYMBOL(rtw89_bd_ram_table_single); static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_bd_ram *bd_ram_table = *info->bd_ram_table; struct rtw89_pci_tx_ring *tx_ring; struct rtw89_pci_rx_ring *rx_ring; struct rtw89_pci_dma_ring *bd_ring; diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 7d033501d4d9..1e19740db8c5 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -750,6 +750,12 @@ struct rtw89_pci_ch_dma_addr_set { struct rtw89_pci_ch_dma_addr rx[RTW89_RXCH_NUM]; }; +struct rtw89_pci_bd_ram { + u8 start_idx; + u8 max_num; + u8 min_num; +}; + struct rtw89_pci_info { enum mac_ax_bd_trunc_mode txbd_trunc_mode; enum mac_ax_bd_trunc_mode rxbd_trunc_mode; @@ -785,6 +791,7 @@ struct rtw89_pci_info { u32 tx_dma_ch_mask; const struct rtw89_pci_bd_idx_addr *bd_idx_addr_low_power; const struct rtw89_pci_ch_dma_addr_set *dma_addr_set; + const struct rtw89_pci_bd_ram (*bd_ram_table)[RTW89_TXCH_NUM]; int (*ltr_set)(struct rtw89_dev *rtwdev, bool en); u32 (*fill_txaddr_info)(struct rtw89_dev *rtwdev, @@ -798,12 +805,6 @@ struct rtw89_pci_info { struct rtw89_pci_isrs *isrs); }; -struct rtw89_pci_bd_ram { - u8 start_idx; - u8 max_num; - u8 min_num; -}; - struct rtw89_pci_tx_data { dma_addr_t dma; }; @@ -1057,6 +1058,8 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) extern const struct dev_pm_ops rtw89_pm_ops; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; +extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM]; +extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM]; struct pci_device_id; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 017710c580c7..ca2b5c17d6da 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -367,6 +367,7 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, } ra->bw_cap = bw_mode; + ra->er_cap = rtwsta->er_cap; ra->mode_ctrl = mode; ra->macid = rtwsta->mac_id; ra->stbc_cap = stbc_en; @@ -4116,6 +4117,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) { + const struct rtw89_chip_info *chip = rtwdev->chip; enum rtw89_phy_idx phy_idx = RTW89_PHY_0; u8 bss_color; @@ -4124,11 +4126,11 @@ void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif bss_color = vif->bss_conf.he_bss_color.color; - rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0, 0x1, - phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_TGT, bss_color, + rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_VLD0, 0x1, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_STAID, + rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_TGT, + bss_color, phy_idx); + rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_STAID, vif->cfg.aid, phy_idx); } diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 5324e645728b..036953f0ec46 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3559,6 +3559,7 @@ #define RR_MOD_IQK GENMASK(19, 4) #define RR_MOD_DPK GENMASK(19, 5) #define RR_MOD_MASK GENMASK(19, 16) +#define RR_MOD_DCK GENMASK(14, 10) #define RR_MOD_RGM GENMASK(13, 4) #define RR_MOD_V_DOWN 0x0 #define RR_MOD_V_STANDBY 0x1 @@ -3572,6 +3573,7 @@ #define RR_MOD_NBW GENMASK(15, 14) #define RR_MOD_M_RXG GENMASK(13, 4) #define RR_MOD_M_RXBB GENMASK(9, 5) +#define RR_MOD_LO_SEL BIT(1) #define RR_MODOPT 0x01 #define RR_MODOPT_M_TXPWR GENMASK(5, 0) #define RR_WLSEL 0x02 @@ -3638,6 +3640,7 @@ #define RR_LUTWA_M2 GENMASK(4, 0) #define RR_LUTWD1 0x3e #define RR_LUTWD0 0x3f +#define RR_LUTWD0_MB GENMASK(11, 6) #define RR_LUTWD0_LB GENMASK(5, 0) #define RR_TM 0x42 #define RR_TM_TRI BIT(19) @@ -3671,6 +3674,8 @@ #define RR_TXRSV_GAPK BIT(19) #define RR_BIAS 0x5e #define RR_BIAS_GAPK BIT(19) +#define RR_TXAC 0x5f +#define RR_TXAC_IQG GENMASK(3, 0) #define RR_BIASA 0x60 #define RR_BIASA_TXG GENMASK(15, 12) #define RR_BIASA_TXA GENMASK(19, 16) @@ -3729,10 +3734,14 @@ #define RR_XALNA2_SW2 GENMASK(9, 8) #define RR_XALNA2_SW GENMASK(1, 0) #define RR_DCK 0x92 +#define RR_DCK_S1 GENMASK(19, 16) +#define RR_DCK_TIA GENMASK(15, 9) #define RR_DCK_DONE GENMASK(7, 5) #define RR_DCK_FINE BIT(1) #define RR_DCK_LV BIT(0) #define RR_DCK1 0x93 +#define RR_DCK1_S1 GENMASK(19, 16) +#define RR_DCK1_TIA GENMASK(15, 9) #define RR_DCK1_DONE BIT(5) #define RR_DCK1_CLR GENMASK(3, 0) #define RR_DCK1_SEL BIT(3) @@ -3781,11 +3790,14 @@ #define RR_LUTDBG 0xdf #define RR_LUTDBG_TIA BIT(12) #define RR_LUTDBG_LOK BIT(2) +#define RR_LUTPLL 0xec +#define RR_CAL_RW BIT(19) #define RR_LUTWE2 0xee #define RR_LUTWE2_RTXBW BIT(2) #define RR_LUTWE 0xef #define RR_LUTWE_LOK BIT(2) #define RR_RFC 0xf0 +#define RR_WCAL BIT(16) #define RR_RFC_CKEN BIT(1) #define R_UPD_P0 0x0000 @@ -4090,12 +4102,13 @@ #define R_MUIC 0x40F8 #define B_MUIC_EN BIT(0) #define R_DCFO 0x4264 -#define B_DCFO GENMASK(1, 0) +#define B_DCFO GENMASK(7, 0) #define R_SEG0CSI 0x42AC -#define B_SEG0CSI_IDX GENMASK(11, 0) +#define B_SEG0CSI_IDX GENMASK(10, 0) #define R_SEG0CSI_EN 0x42C4 #define B_SEG0CSI_EN BIT(23) #define R_BSS_CLR_MAP 0x43ac +#define R_BSS_CLR_MAP_V1 0x43B0 #define B_BSS_CLR_MAP_VLD0 BIT(28) #define B_BSS_CLR_MAP_TGT GENMASK(27, 22) #define B_BSS_CLR_MAP_STAID GENMASK(21, 11) @@ -4725,6 +4738,7 @@ #define R_DRCK_FH 0xC094 #define B_DRCK_LAT BIT(9) #define R_DRCK 0xC0C4 +#define B_DRCK_MUL GENMASK(21, 17) #define B_DRCK_IDLE BIT(9) #define B_DRCK_EN BIT(6) #define B_DRCK_VAL GENMASK(4, 0) @@ -4742,9 +4756,13 @@ #define B_PATH0_SAMPL_DLY_T_MSK_V1 GENMASK(27, 26) #define R_P0_CFCH_BW0 0xC0D4 #define B_P0_CFCH_BW0 GENMASK(27, 26) +#define B_P0_CFCH_EN GENMASK(14, 11) +#define B_P0_CFCH_CTL GENMASK(10, 7) #define R_P0_CFCH_BW1 0xC0D8 #define B_P0_CFCH_EX BIT(13) #define B_P0_CFCH_BW1 GENMASK(8, 5) +#define R_ADCMOD 0xC0E8 +#define B_ADCMOD_LP GENMASK(31, 16) #define R_ADDCK0D 0xC0F0 #define B_ADDCK0D_VAL2 GENMASK(31, 26) #define B_ADDCK0D_VAL GENMASK(25, 16) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index eff6519cf019..45119c512a05 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -1035,7 +1035,7 @@ static void rtw8852a_spur_elimination(struct rtw89_dev *rtwdev, u8 central_ch) 0x210); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, B_P1_NBIIDX_VAL, 0x210); - rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, 0xfff, 0x7c0); + rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, B_SEG0CSI_IDX, 0x7c0); rtw89_phy_write32_mask(rtwdev, R_P0_NBIIDX, B_P0_NBIIDX_NOTCH_EN, 0x1); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, @@ -1047,7 +1047,7 @@ static void rtw8852a_spur_elimination(struct rtw89_dev *rtwdev, u8 central_ch) 0x210); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, B_P1_NBIIDX_VAL, 0x210); - rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, 0xfff, 0x40); + rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, B_SEG0CSI_IDX, 0x40); rtw89_phy_write32_mask(rtwdev, R_P0_NBIIDX, B_P0_NBIIDX_NOTCH_EN, 0x1); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, @@ -1059,7 +1059,7 @@ static void rtw8852a_spur_elimination(struct rtw89_dev *rtwdev, u8 central_ch) 0x2d0); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, B_P1_NBIIDX_VAL, 0x2d0); - rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, 0xfff, 0x740); + rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, B_SEG0CSI_IDX, 0x740); rtw89_phy_write32_mask(rtwdev, R_P0_NBIIDX, B_P0_NBIIDX_NOTCH_EN, 0x1); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, @@ -1878,9 +1878,13 @@ static void rtw8852a_btc_update_bt_cnt(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; u32 val; + if (ver->fcxbtcrpt != 1) + return; + val = rtw89_read32(rtwdev, R_AX_BT_STAST_HIGH); cx->cnt_bt[BTC_BCNT_HIPRI_TX] = FIELD_GET(B_AX_STATIS_BT_HI_TX_MASK, val); cx->cnt_bt[BTC_BCNT_HIPRI_RX] = FIELD_GET(B_AX_STATIS_BT_HI_RX_MASK, val); @@ -2106,20 +2110,6 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, - .btc_fwinfo_buf = 1024, - - .fcxbtcrpt_ver = 1, - .fcxtdma_ver = 1, - .fcxslots_ver = 1, - .fcxcysta_ver = 2, - .fcxstep_ver = 2, - .fcxnullsta_ver = 1, - .fcxmreg_ver = 1, - .fcxgpiodbg_ver = 1, - .fcxbtver_ver = 1, - .fcxbtscan_ver = 1, - .fcxbtafh_ver = 1, - .fcxbtdevinfo_ver = 1, .afh_guard_ch = 6, .wl_rssi_thres = rtw89_btc_8852a_wl_rssi_thres, @@ -2149,6 +2139,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .dcfo_comp_sft = 3, .imr_info = &rtw8852a_imr_info, .rrsr_cfgs = &rtw8852a_rrsr_cfgs, + .bss_clr_map_reg = R_BSS_CLR_MAP, .dma_ch_mask = 0, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852a, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c index 582ff0d3a9ea..cd6c39b7f802 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c @@ -1643,7 +1643,7 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]==========IQK strat!!!!!==========\n"); + "[IQK]==========IQK start!!!!!==========\n"); iqk_info->iqk_times++; iqk_info->kcount = 0; iqk_info->version = RTW8852A_IQK_VER; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index 0cd8c0c44d19..d835a44a1d0d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -44,6 +44,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set, + .bd_ram_table = &rtw89_bd_ram_table_dual, .ltr_set = rtw89_pci_ltr_set, .fill_txaddr_info = rtw89_pci_fill_txaddr_info, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index b635ac1d1ca2..c6345228d049 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2423,7 +2423,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .btc_update_bt_cnt = rtw8852b_btc_update_bt_cnt, .btc_wl_s1_standby = rtw8852b_btc_wl_s1_standby, .btc_set_wl_rx_gain = rtw8852b_btc_set_wl_rx_gain, - .btc_set_policy = rtw89_btc_set_policy, + .btc_set_policy = rtw89_btc_set_policy_v1, }; const struct rtw89_chip_info rtw8852b_chip_info = { @@ -2437,6 +2437,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, .dle_mem = rtw8852b_dle_mem_pcie, + .wde_qempty_acq_num = 4, + .wde_qempty_mgq_sel = 4, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, @@ -2483,20 +2485,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .btcx_desired = 0x5, .scbd = 0x1, .mailbox = 0x1, - .btc_fwinfo_buf = 1024, - - .fcxbtcrpt_ver = 1, - .fcxtdma_ver = 1, - .fcxslots_ver = 1, - .fcxcysta_ver = 2, - .fcxstep_ver = 2, - .fcxnullsta_ver = 1, - .fcxmreg_ver = 1, - .fcxgpiodbg_ver = 1, - .fcxbtver_ver = 1, - .fcxbtscan_ver = 1, - .fcxbtafh_ver = 1, - .fcxbtdevinfo_ver = 1, + .afh_guard_ch = 6, .wl_rssi_thres = rtw89_btc_8852b_wl_rssi_thres, .bt_rssi_thres = rtw89_btc_8852b_bt_rssi_thres, @@ -2525,6 +2514,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dcfo_comp_sft = 3, .imr_info = &rtw8852b_imr_info, .rrsr_cfgs = &rtw8852b_rrsr_cfgs, + .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index 0ef2ca8efeb0..ecf39d2d9f81 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -46,6 +46,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set, + .bd_ram_table = &rtw89_bd_ram_table_single, .ltr_set = rtw89_pci_ltr_set, .fill_txaddr_info = rtw89_pci_fill_txaddr_info, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index a87482cc25f5..00fbb6535506 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2915,20 +2915,6 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, - .btc_fwinfo_buf = 1280, - - .fcxbtcrpt_ver = 4, - .fcxtdma_ver = 3, - .fcxslots_ver = 1, - .fcxcysta_ver = 3, - .fcxstep_ver = 3, - .fcxnullsta_ver = 2, - .fcxmreg_ver = 1, - .fcxgpiodbg_ver = 1, - .fcxbtver_ver = 1, - .fcxbtscan_ver = 1, - .fcxbtafh_ver = 1, - .fcxbtdevinfo_ver = 1, .afh_guard_ch = 6, .wl_rssi_thres = rtw89_btc_8852c_wl_rssi_thres, @@ -2959,6 +2945,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .dcfo_comp_sft = 5, .imr_info = &rtw8852c_imr_info, .rrsr_cfgs = &rtw8852c_rrsr_cfgs, + .bss_clr_map_reg = R_BSS_CLR_MAP, .dma_ch_mask = 0, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852c, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c index 60cd676fe22c..2c0bc3a4ab3b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c @@ -11,6 +11,15 @@ #include "rtw8852c_rfk_table.h" #include "rtw8852c_table.h" +struct rxck_def { + u32 ctl; + u32 en; + u32 bw0; + u32 bw1; + u32 mul; + u32 lp; +}; + #define _TSSI_DE_MASK GENMASK(21, 12) static const u32 _tssi_de_cck_long[RF_PATH_NUM_8852C] = {0x5858, 0x7858}; static const u32 _tssi_de_cck_short[RF_PATH_NUM_8852C] = {0x5860, 0x7860}; @@ -26,7 +35,7 @@ static const u32 rtw8852c_backup_bb_regs[] = { }; static const u32 rtw8852c_backup_rf_regs[] = { - 0xdf, 0x8f, 0x97, 0xa3, 0x5, 0x10005 + 0xdf, 0x5f, 0x8f, 0x97, 0xa3, 0x5, 0x10005 }; #define BACKUP_BB_REGS_NR ARRAY_SIZE(rtw8852c_backup_bb_regs) @@ -59,6 +68,13 @@ static const u32 dpk_par_regs[RTW89_DPK_RF_PATH][4] = { {0x81a8, 0x81c4, 0x81c8, 0x81e8}, }; +static const u8 _dck_addr_bs[RF_PATH_NUM_8852C] = {0x0, 0x10}; +static const u8 _dck_addr[RF_PATH_NUM_8852C] = {0xc, 0x1c}; + +static const struct rxck_def _ck480M = {0x8, 0x2, 0x3, 0xf, 0x0, 0x9}; +static const struct rxck_def _ck960M = {0x8, 0x2, 0x2, 0x8, 0x0, 0x9}; +static const struct rxck_def _ck1920M = {0x8, 0x0, 0x2, 0x4, 0x6, 0x9}; + static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]dbcc_en: %x, PHY%d\n", @@ -337,7 +353,7 @@ static void _dack_reload_by_path(struct rtw89_dev *rtwdev, (dack->dadck_d[path][index] << 14); addr = 0xc210 + offset; rtw89_phy_write32(rtwdev, addr, val32); - rtw89_phy_write32_set(rtwdev, addr, BIT(1)); + rtw89_phy_write32_set(rtwdev, addr, BIT(0)); } static void _dack_reload(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) @@ -437,6 +453,8 @@ static void rtw8852c_txck_force(struct rtw89_dev *rtwdev, u8 path, bool force, static void rtw8852c_rxck_force(struct rtw89_dev *rtwdev, u8 path, bool force, enum adc_ck ck) { + const struct rxck_def *def; + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x0); if (!force) @@ -444,6 +462,26 @@ static void rtw8852c_rxck_force(struct rtw89_dev *rtwdev, u8 path, bool force, rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_VAL, ck); rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x1); + + switch (ck) { + case ADC_480M: + def = &_ck480M; + break; + case ADC_960M: + def = &_ck960M; + break; + case ADC_1920M: + default: + def = &_ck1920M; + break; + } + + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_CTL, def->ctl); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_EN, def->en); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_BW0, def->bw0); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 | (path << 8), B_P0_CFCH_BW1, def->bw1); + rtw89_phy_write32_mask(rtwdev, R_DRCK | (path << 8), B_DRCK_MUL, def->mul); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD | (path << 8), B_ADCMOD_LP, def->lp); } static bool _check_dack_done(struct rtw89_dev *rtwdev, bool s0) @@ -627,8 +665,6 @@ static void _iqk_rxk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_DPD_GDIS, 0x1); rtw8852c_rxck_force(rtwdev, path, true, ADC_480M); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_ACK_VAL, 0x0); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 + (path << 8), B_P0_CFCH_BW0, 0x3); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 + (path << 8), B_P0_CFCH_BW1, 0xf); rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x1); break; @@ -636,8 +672,6 @@ static void _iqk_rxk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_DPD_GDIS, 0x1); rtw8852c_rxck_force(rtwdev, path, true, ADC_960M); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_ACK_VAL, 0x1); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 + (path << 8), B_P0_CFCH_BW0, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 + (path << 8), B_P0_CFCH_BW1, 0xd); rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x1); break; @@ -645,8 +679,6 @@ static void _iqk_rxk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_DPD_GDIS, 0x1); rtw8852c_rxck_force(rtwdev, path, true, ADC_1920M); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_ACK_VAL, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 + (path << 8), B_P0_CFCH_BW0, 0x1); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 + (path << 8), B_P0_CFCH_BW1, 0xb); rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x1); break; @@ -1410,8 +1442,6 @@ static void _iqk_macbb_setting(struct rtw89_dev *rtwdev, rtw8852c_rxck_force(rtwdev, path, true, ADC_1920M); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK | (path << 13), B_ACK_VAL, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_BW0, 0x1); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 | (path << 8), B_P0_CFCH_BW1, 0xb); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW | (path << 13), B_P0_NRBW_DBG, 0x1); rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x1f); rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x13); @@ -1536,6 +1566,155 @@ static void _iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool forc } } +static void _rx_dck_value_rewrite(struct rtw89_dev *rtwdev, u8 path, u8 addr, + u8 val_i, u8 val_q) +{ + u32 ofst_val; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] rewrite val_i = 0x%x, val_q = 0x%x\n", val_i, val_q); + + /* val_i and val_q are 7 bits, and target is 6 bits. */ + ofst_val = u32_encode_bits(val_q >> 1, RR_LUTWD0_MB) | + u32_encode_bits(val_i >> 1, RR_LUTWD0_LB); + + rtw89_write_rf(rtwdev, path, RR_LUTPLL, RR_CAL_RW, 0x1); + rtw89_write_rf(rtwdev, path, RR_RFC, RR_WCAL, 0x1); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_FINE, 0x1); + rtw89_write_rf(rtwdev, path, RR_LUTWA, MASKBYTE0, addr); + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, ofst_val); + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, ofst_val); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_FINE, 0x0); + rtw89_write_rf(rtwdev, path, RR_RFC, RR_WCAL, 0x0); + rtw89_write_rf(rtwdev, path, RR_LUTPLL, RR_CAL_RW, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] Final val_i = 0x%x, val_q = 0x%x\n", + u32_get_bits(ofst_val, RR_LUTWD0_LB) << 1, + u32_get_bits(ofst_val, RR_LUTWD0_MB) << 1); +} + +static bool _rx_dck_rek_check(struct rtw89_dev *rtwdev, u8 path) +{ + u8 i_even_bs, q_even_bs; + u8 i_odd_bs, q_odd_bs; + u8 i_even, q_even; + u8 i_odd, q_odd; + const u8 th = 10; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8852C; i++) { + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr_bs[i]); + i_even_bs = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_even_bs = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_even_bs/ q_even_bs = 0x%x/ 0x%x\n", + _dck_addr_bs[i], i_even_bs, q_even_bs); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr[i]); + i_even = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_even = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_even/ q_even = 0x%x/ 0x%x\n", + _dck_addr[i], i_even, q_even); + + if (abs(i_even_bs - i_even) > th || abs(q_even_bs - q_even) > th) + return true; + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr_bs[i] + 1); + i_odd_bs = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_odd_bs = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_odd_bs/ q_odd_bs = 0x%x/ 0x%x\n", + _dck_addr_bs[i] + 1, i_odd_bs, q_odd_bs); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr[i] + 1); + i_odd = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_odd = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_odd/ q_odd = 0x%x/ 0x%x\n", + _dck_addr[i] + 1, i_odd, q_odd); + + if (abs(i_odd_bs - i_odd) > th || abs(q_odd_bs - q_odd) > th) + return true; + } + + return false; +} + +static void _rx_dck_fix_if_need(struct rtw89_dev *rtwdev, u8 path, u8 addr, + u8 val_i_bs, u8 val_q_bs, u8 val_i, u8 val_q) +{ + const u8 th = 10; + + if ((abs(val_i_bs - val_i) < th) && (abs(val_q_bs - val_q) <= th)) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] offset check PASS!!\n"); + return; + } + + if (abs(val_i_bs - val_i) > th) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] val_i over TH (0x%x / 0x%x)\n", val_i_bs, val_i); + val_i = val_i_bs; + } + + if (abs(val_q_bs - val_q) > th) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] val_q over TH (0x%x / 0x%x)\n", val_q_bs, val_q); + val_q = val_q_bs; + } + + _rx_dck_value_rewrite(rtwdev, path, addr, val_i, val_q); +} + +static void _rx_dck_recover(struct rtw89_dev *rtwdev, u8 path) +{ + u8 i_even_bs, q_even_bs; + u8 i_odd_bs, q_odd_bs; + u8 i_even, q_even; + u8 i_odd, q_odd; + u8 i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] ===> recovery\n"); + + for (i = 0; i < RF_PATH_NUM_8852C; i++) { + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr_bs[i]); + i_even_bs = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_even_bs = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr_bs[i] + 1); + i_odd_bs = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_odd_bs = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_even_bs/ q_even_bs = 0x%x/ 0x%x\n", + _dck_addr_bs[i], i_even_bs, q_even_bs); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr[i]); + i_even = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_even = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_even/ q_even = 0x%x/ 0x%x\n", + _dck_addr[i], i_even, q_even); + _rx_dck_fix_if_need(rtwdev, path, _dck_addr[i], + i_even_bs, q_even_bs, i_even, q_even); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_odd_bs/ q_odd_bs = 0x%x/ 0x%x\n", + _dck_addr_bs[i] + 1, i_odd_bs, q_odd_bs); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr[i] + 1); + i_odd = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_odd = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_odd/ q_odd = 0x%x/ 0x%x\n", + _dck_addr[i] + 1, i_odd, q_odd); + _rx_dck_fix_if_need(rtwdev, path, _dck_addr[i] + 1, + i_odd_bs, q_odd_bs, i_odd, q_odd); + } +} + static void _rx_dck_toggle(struct rtw89_dev *rtwdev, u8 path) { int ret; @@ -1573,11 +1752,42 @@ static void _set_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 pat } } +static +u8 _rx_dck_channel_calc(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan) +{ + u8 target_ch = 0; + + if (chan->band_type == RTW89_BAND_5G) { + if (chan->channel >= 36 && chan->channel <= 64) { + target_ch = 100; + } else if (chan->channel >= 100 && chan->channel <= 144) { + target_ch = chan->channel + 32; + if (target_ch > 144) + target_ch = chan->channel + 33; + } else if (chan->channel >= 149 && chan->channel <= 177) { + target_ch = chan->channel - 33; + } + } else if (chan->band_type == RTW89_BAND_6G) { + if (chan->channel >= 1 && chan->channel <= 125) + target_ch = chan->channel + 32; + else + target_ch = chan->channel - 32; + } else { + target_ch = chan->channel; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] cur_ch / target_ch = %d / %d\n", + chan->channel, target_ch); + + return target_ch; +} + #define RTW8852C_RF_REL_VERSION 34 -#define RTW8852C_DPK_VER 0x10 +#define RTW8852C_DPK_VER 0xf #define RTW8852C_DPK_TH_AVG_NUM 4 #define RTW8852C_DPK_RF_PATH 2 -#define RTW8852C_DPK_KIP_REG_NUM 5 +#define RTW8852C_DPK_KIP_REG_NUM 7 #define RTW8852C_DPK_RXSRAM_DBG 0 enum rtw8852c_dpk_id { @@ -1614,6 +1824,12 @@ enum dpk_agc_step { DPK_AGC_STEP_SET_TX_GAIN, }; +enum dpk_pas_result { + DPK_PAS_NOR, + DPK_PAS_GT, + DPK_PAS_LT, +}; + static void _rf_direct_cntrl(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool is_bybb) { @@ -1730,8 +1946,6 @@ static void _dpk_bb_afe_setting(struct rtw89_dev *rtwdev, /*4. Set ADC clk*/ rtw8852c_rxck_force(rtwdev, path, true, ADC_1920M); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 + (path << 8), B_P0_CFCH_BW0, 0x1); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 + (path << 8), B_P0_CFCH_BW1, 0xb); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x1); rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, MASKBYTE3, 0x1f); @@ -1872,12 +2086,11 @@ static void _dpk_rf_setting(struct rtw89_dev *rtwdev, u8 gain, 0x50101 | BIT(rtwdev->dbcc_en)); rtw89_write_rf(rtwdev, path, RR_MOD_V1, RR_MOD_MASK, RF_DPK); - if (dpk->bp[path][kidx].band == RTW89_BAND_6G && dpk->bp[path][kidx].ch >= 161) { + if (dpk->bp[path][kidx].band == RTW89_BAND_6G && dpk->bp[path][kidx].ch >= 161) rtw89_write_rf(rtwdev, path, RR_IQGEN, RR_IQGEN_BIAS, 0x8); - rtw89_write_rf(rtwdev, path, RR_LOGEN, RR_LOGEN_RPT, 0xd); - } else { - rtw89_write_rf(rtwdev, path, RR_LOGEN, RR_LOGEN_RPT, 0xd); - } + + rtw89_write_rf(rtwdev, path, RR_LOGEN, RR_LOGEN_RPT, 0xd); + rtw89_write_rf(rtwdev, path, RR_TXAC, RR_TXAC_IQG, 0x8); rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RXA2_ATT, 0x0); rtw89_write_rf(rtwdev, path, RR_TXIQK, RR_TXIQK_ATT2, 0x3); @@ -2024,9 +2237,10 @@ static u8 _dpk_gainloss(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, return _dpk_gainloss_read(rtwdev); } -static bool _dpk_pas_read(struct rtw89_dev *rtwdev, bool is_check) +static enum dpk_pas_result _dpk_pas_read(struct rtw89_dev *rtwdev, bool is_check) { u32 val1_i = 0, val1_q = 0, val2_i = 0, val2_q = 0; + u32 val1_sqrt_sum, val2_sqrt_sum; u8 i; rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, MASKBYTE2, 0x06); @@ -2057,15 +2271,25 @@ static bool _dpk_pas_read(struct rtw89_dev *rtwdev, bool is_check) } } - if (val1_i * val1_i + val1_q * val1_q >= (val2_i * val2_i + val2_q * val2_q) * 8 / 5) - return true; + val1_sqrt_sum = val1_i * val1_i + val1_q * val1_q; + val2_sqrt_sum = val2_i * val2_i + val2_q * val2_q; + + if (val1_sqrt_sum < val2_sqrt_sum) + return DPK_PAS_LT; + else if (val1_sqrt_sum >= val2_sqrt_sum * 8 / 5) + return DPK_PAS_GT; else - return false; + return DPK_PAS_NOR; } static bool _dpk_kip_set_rxagc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, enum rtw89_rf_path path, u8 kidx) { + _dpk_kip_control_rfc(rtwdev, path, false); + rtw89_phy_write32_mask(rtwdev, R_KIP_MOD, B_KIP_MOD, + rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK)); + _dpk_kip_control_rfc(rtwdev, path, true); + _dpk_one_shot(rtwdev, phy, path, D_RXAGC); return _dpk_sync_check(rtwdev, path, kidx); @@ -2103,6 +2327,7 @@ static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 tmp_dbm = init_xdbm, tmp_gl_idx = 0; u8 tmp_rxbb; u8 goout = 0, agc_cnt = 0; + enum dpk_pas_result pas; u16 dgain = 0; bool is_fail = false; int limit = 200; @@ -2138,9 +2363,13 @@ static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, case DPK_AGC_STEP_GAIN_LOSS_IDX: tmp_gl_idx = _dpk_gainloss(rtwdev, phy, path, kidx); + pas = _dpk_pas_read(rtwdev, true); - if ((tmp_gl_idx == 0 && _dpk_pas_read(rtwdev, true)) || - tmp_gl_idx >= 7) + if (pas == DPK_PAS_LT && tmp_gl_idx > 0) + step = DPK_AGC_STEP_GL_LT_CRITERION; + else if (pas == DPK_PAS_GT && tmp_gl_idx == 0) + step = DPK_AGC_STEP_GL_GT_CRITERION; + else if (tmp_gl_idx >= 7) step = DPK_AGC_STEP_GL_GT_CRITERION; else if (tmp_gl_idx == 0) step = DPK_AGC_STEP_GL_LT_CRITERION; @@ -2467,12 +2696,14 @@ static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, enum rtw89_phy_idx phy, u8 kpath) { struct rtw89_dpk_info *dpk = &rtwdev->dpk; - static const u32 kip_reg[] = {0x813c, 0x8124, 0x8120, 0xc0d4, 0xc0d8}; + static const u32 kip_reg[] = {0x813c, 0x8124, 0x8120, 0xc0c4, 0xc0e8, 0xc0d4, 0xc0d8}; u32 backup_rf_val[RTW8852C_DPK_RF_PATH][BACKUP_RF_REGS_NR]; u32 kip_bkup[RTW8852C_DPK_RF_PATH][RTW8852C_DPK_KIP_REG_NUM] = {}; u8 path; bool is_fail = true, reloaded[RTW8852C_DPK_RF_PATH] = {false}; + static_assert(ARRAY_SIZE(kip_reg) == RTW8852C_DPK_KIP_REG_NUM); + if (dpk->is_dpk_reload_en) { for (path = 0; path < RTW8852C_DPK_RF_PATH; path++) { if (!(kpath & BIT(path))) @@ -3875,11 +4106,14 @@ void rtw8852c_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) #define RXDCK_VER_8852C 0xe -void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_afe) +static void _rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + bool is_afe, u8 retry_limit) { struct rtw89_rx_dck_info *rx_dck = &rtwdev->rx_dck; u8 path, kpath; u32 rf_reg5; + bool is_fail; + u8 rek_cnt; kpath = _kpath(rtwdev, phy); rtw89_debug(rtwdev, RTW89_DBG_RFK, @@ -3896,7 +4130,27 @@ void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_a B_P0_TSSI_TRK_EN, 0x1); rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX); - _set_rx_dck(rtwdev, phy, path, is_afe); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_LO_SEL, rtwdev->dbcc_en); + + for (rek_cnt = 0; rek_cnt < retry_limit; rek_cnt++) { + _set_rx_dck(rtwdev, phy, path, is_afe); + + /* To reduce IO of dck_rek_check(), the last try is seen + * as failure always, and then do recovery procedure. + */ + if (rek_cnt == retry_limit - 1) { + _rx_dck_recover(rtwdev, path); + break; + } + + is_fail = _rx_dck_rek_check(rtwdev, path); + if (!is_fail) + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] rek_cnt[%d]=%d", + path, rek_cnt); + rx_dck->thermal[path] = ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5); @@ -3906,15 +4160,31 @@ void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_a } } -#define RTW8852C_RX_DCK_TH 8 +void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_afe) +{ + _rx_dck(rtwdev, phy, is_afe, 1); +} + +#define RTW8852C_RX_DCK_TH 12 void rtw8852c_rx_dck_track(struct rtw89_dev *rtwdev) { + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); struct rtw89_rx_dck_info *rx_dck = &rtwdev->rx_dck; + enum rtw89_phy_idx phy_idx = RTW89_PHY_0; + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); + u8 dck_channel; u8 cur_thermal; + u32 tx_en; int delta; int path; + if (chan->band_type == RTW89_BAND_2G) + return; + + if (rtwdev->scanning) + return; + for (path = 0; path < RF_PATH_NUM_8852C; path++) { cur_thermal = ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); @@ -3924,11 +4194,28 @@ void rtw8852c_rx_dck_track(struct rtw89_dev *rtwdev) "[RX_DCK] path=%d current thermal=0x%x delta=0x%x\n", path, cur_thermal, delta); - if (delta >= RTW8852C_RX_DCK_TH) { - rtw8852c_rx_dck(rtwdev, RTW89_PHY_0, false); - return; - } + if (delta >= RTW8852C_RX_DCK_TH) + goto trigger_rx_dck; } + + return; + +trigger_rx_dck: + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_START); + rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); + + for (path = 0; path < RF_PATH_NUM_8852C; path++) { + dck_channel = _rx_dck_channel_calc(rtwdev, chan); + _ctrl_ch(rtwdev, RTW89_PHY_0, dck_channel, chan->band_type); + } + + _rx_dck(rtwdev, RTW89_PHY_0, false, 20); + + for (path = 0; path < RF_PATH_NUM_8852C; path++) + _ctrl_ch(rtwdev, RTW89_PHY_0, chan->channel, chan->band_type); + + rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_STOP); } void rtw8852c_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 35901f64d17d..80490a5437df 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -53,6 +53,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = &rtw8852c_bd_idx_addr_low_power, .dma_addr_set = &rtw89_pci_ch_dma_addr_set_v1, + .bd_ram_table = &rtw89_bd_ram_table_dual, .ltr_set = rtw89_pci_ltr_set_v1, .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 9d4c6b6fa125..98eb9607cd21 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -75,7 +75,9 @@ #define RTW89_TXWD_INFO0_DATA_BW GENMASK(29, 28) #define RTW89_TXWD_INFO0_GI_LTF GENMASK(27, 25) #define RTW89_TXWD_INFO0_DATA_RATE GENMASK(24, 16) +#define RTW89_TXWD_INFO0_DATA_ER BIT(15) #define RTW89_TXWD_INFO0_DISDATAFB BIT(10) +#define RTW89_TXWD_INFO0_DATA_BW_ER BIT(8) #define RTW89_TXWD_INFO0_MULTIPORT_ID GENMASK(6, 4) /* TX WD INFO DWORD 1 */ diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c index 8a3d86897ea8..45ac9371f262 100644 --- a/drivers/net/wireless/rsi/rsi_91x_coex.c +++ b/drivers/net/wireless/rsi/rsi_91x_coex.c @@ -160,6 +160,7 @@ int rsi_coex_attach(struct rsi_common *common) rsi_coex_scheduler_thread, "Coex-Tx-Thread")) { rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__); + kfree(coex_cb); return -EINVAL; } return 0; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 1b532e00a56f..7fb2f9513476 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1328,7 +1328,7 @@ static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb, } else { ++dev->stats.tx_packets; dev->stats.tx_bytes += skb->len; - kfree_skb(skb); + dev_kfree_skb_irq(skb); if (this->tx_buffer_cnt < 2) netif_stop_queue(dev); diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index c9be1657f03d..ebfa12f69501 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -115,6 +115,32 @@ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ }) +#define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0) + +/** + * FIELD_PREP_CONST() - prepare a constant bitfield element + * @_mask: shifted mask defining the field's length and position + * @_val: value to put in the field + * + * FIELD_PREP_CONST() masks and shifts up the value. The result should + * be combined with other fields of the bitfield using logical OR. + * + * Unlike FIELD_PREP() this is a constant expression and can therefore + * be used in initializers. Error checking is less comfortable for this + * version, and non-constant masks cannot be used. + */ +#define FIELD_PREP_CONST(_mask, _val) \ + ( \ + /* mask must be non-zero */ \ + BUILD_BUG_ON_ZERO((_mask) == 0) + \ + /* check if value fits */ \ + BUILD_BUG_ON_ZERO(~((_mask) >> __bf_shf(_mask)) & (_val)) + \ + /* check if mask is contiguous */ \ + __BF_CHECK_POW2((_mask) + (1ULL << __bf_shf(_mask))) + \ + /* and create the value */ \ + (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)) \ + ) + /** * FIELD_GET() - extract a bitfield element * @_mask: shifted mask defining the field's length and position diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h index b939bd2750a0..fd0b0605cf90 100644 --- a/include/linux/soc/mediatek/mtk_wed.h +++ b/include/linux/soc/mediatek/mtk_wed.h @@ -103,7 +103,6 @@ struct mtk_wed_device { struct { int size; - struct page_frag_cache rx_page; struct mtk_rxbm_desc *desc; dma_addr_t desc_phys; } rx_buf_ring; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 03d4f4deadae..54a77d906b2d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1075,7 +1075,6 @@ struct survey_info { s8 noise; }; -#define CFG80211_MAX_WEP_KEYS 4 #define CFG80211_MAX_NUM_AKM_SUITES 10 /** @@ -1099,9 +1098,6 @@ struct survey_info { * port frames over NL80211 instead of the network interface. * @control_port_no_preauth: disables pre-auth rx over the nl80211 control * port for mac80211 - * @wep_keys: static WEP keys, if not NULL points to an array of - * CFG80211_MAX_WEP_KEYS WEP keys - * @wep_tx_key: key index (0..3) of the default TX static WEP key * @psk: PSK (for devices supporting 4-way-handshake offload) * @sae_pwd: password for SAE authentication (for devices supporting SAE * offload) @@ -1134,8 +1130,6 @@ struct cfg80211_crypto_settings { bool control_port_no_encrypt; bool control_port_over_nl80211; bool control_port_no_preauth; - struct key_params *wep_keys; - int wep_tx_key; const u8 *psk; const u8 *sae_pwd; u8 sae_pwd_len; @@ -4683,13 +4677,12 @@ struct cfg80211_ops { * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels. * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in * beaconing mode (AP, IBSS, Mesh, ...). - * @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation - * before connection. * @WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK: The device supports bigger kek and kck keys * @WIPHY_FLAG_SUPPORTS_MLO: This is a temporary flag gating the MLO APIs, * in order to not have them reachable in normal drivers, until we have * complete feature/interface combinations/etc. advertisement. No driver * should set this flag for now. + * @WIPHY_FLAG_SUPPORTS_EXT_KCK_32: The device supports 32-byte KCK keys. */ enum wiphy_flags { WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0), @@ -4702,7 +4695,7 @@ enum wiphy_flags { WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), WIPHY_FLAG_IBSS_RSN = BIT(8), WIPHY_FLAG_MESH_AUTH = BIT(10), - /* use hole at 11 */ + WIPHY_FLAG_SUPPORTS_EXT_KCK_32 = BIT(11), /* use hole at 12 */ WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), WIPHY_FLAG_AP_UAPSD = BIT(14), @@ -4715,7 +4708,6 @@ enum wiphy_flags { WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21), WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22), WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23), - WIPHY_FLAG_HAS_STATIC_WEP = BIT(24), }; /** @@ -7783,7 +7775,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, /** * cfg80211_del_sta_sinfo - notify userspace about deletion of a station * @dev: the netdev - * @mac_addr: the station's address + * @mac_addr: the station's address. For MLD station, MLD address is used. * @sinfo: the station information/statistics * @gfp: allocation flags */ @@ -7794,7 +7786,7 @@ void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr, * cfg80211_del_sta - notify userspace about deletion of a station * * @dev: the netdev - * @mac_addr: the station's address + * @mac_addr: the station's address. For MLD station, MLD address is used. * @gfp: allocation flags */ static inline void cfg80211_del_sta(struct net_device *dev, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e3235b9c02c2..2635e6de8101 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -653,6 +653,23 @@ struct ieee80211_fils_discovery { * write-protected by sdata_lock and local->mtx so holding either is fine * for read access. * @color_change_color: the bss color that will be used after the change. + * @vht_su_beamformer: in AP mode, does this BSS support operation as an VHT SU + * beamformer + * @vht_su_beamformee: in AP mode, does this BSS support operation as an VHT SU + * beamformee + * @vht_mu_beamformer: in AP mode, does this BSS support operation as an VHT MU + * beamformer + * @vht_mu_beamformee: in AP mode, does this BSS support operation as an VHT MU + * beamformee + * @he_su_beamformer: in AP-mode, does this BSS support operation as an HE SU + * beamformer + * @he_su_beamformee: in AP-mode, does this BSS support operation as an HE SU + * beamformee + * @he_mu_beamformer: in AP-mode, does this BSS support operation as an HE MU + * beamformer + * @he_full_ul_mumimo: does this BSS support the reception (AP) or transmission + * (non-AP STA) of an HE TB PPDU on an RU that spans the entire PPDU + * bandwidth */ struct ieee80211_bss_conf { const u8 *bssid; @@ -726,6 +743,15 @@ struct ieee80211_bss_conf { bool color_change_active; u8 color_change_color; + + bool vht_su_beamformer; + bool vht_su_beamformee; + bool vht_mu_beamformer; + bool vht_mu_beamformee; + bool he_su_beamformer; + bool he_su_beamformee; + bool he_mu_beamformer; + bool he_full_ul_mumimo; }; /** @@ -1436,6 +1462,7 @@ enum mac80211_rx_encoding { RX_ENC_HT, RX_ENC_VHT, RX_ENC_HE, + RX_ENC_EHT, }; /** @@ -1469,7 +1496,7 @@ enum mac80211_rx_encoding { * @antenna: antenna used * @rate_idx: index of data rate into band's supported rates or MCS index if * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) - * @nss: number of streams (VHT and HE only) + * @nss: number of streams (VHT, HE and EHT only) * @flag: %RX_FLAG_\* * @encoding: &enum mac80211_rx_encoding * @bw: &enum rate_info_bw @@ -1477,6 +1504,9 @@ enum mac80211_rx_encoding { * @he_ru: HE RU, from &enum nl80211_he_ru_alloc * @he_gi: HE GI, from &enum nl80211_he_gi * @he_dcm: HE DCM value + * @eht: EHT specific rate information + * @eht.ru: EHT RU, from &enum nl80211_eht_ru_alloc + * @eht.gi: EHT GI, from &enum nl80211_eht_gi * @rx_flags: internal RX flags for mac80211 * @ampdu_reference: A-MPDU reference number, must be a different value for * each A-MPDU but the same for each subframe within one A-MPDU @@ -1498,8 +1528,18 @@ struct ieee80211_rx_status { u32 flag; u16 freq: 13, freq_offset: 1; u8 enc_flags; - u8 encoding:2, bw:3, he_ru:3; - u8 he_gi:2, he_dcm:1; + u8 encoding:3, bw:4; + union { + struct { + u8 he_ru:3; + u8 he_gi:2; + u8 he_dcm:1; + }; + struct { + u8 ru:4; + u8 gi:2; + } eht; + }; u8 rate_idx; u8 nss; u8 rx_flags; @@ -5884,9 +5924,6 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, * This function iterates over the interfaces associated with a given * hardware that are currently active and calls the callback for them. * This version can only be used while holding the wiphy mutex. - * The driver must not call this with a lock held that it can also take in - * response to callbacks from mac80211, and it must not call this within - * callbacks made by mac80211 - both would result in deadlocks. * * @hw: the hardware struct of which the interfaces should be iterated over * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags @@ -5901,24 +5938,6 @@ void ieee80211_iterate_active_interfaces_mtx(struct ieee80211_hw *hw, void *data); /** - * ieee80211_iterate_stations - iterate stations - * - * This function iterates over all stations associated with a given - * hardware that are currently uploaded to the driver and calls the callback - * function for them. - * This function allows the iterator function to sleep, when the iterator - * function is atomic @ieee80211_iterate_stations_atomic can be used. - * - * @hw: the hardware struct of which the interfaces should be iterated over - * @iterator: the iterator function to call, cannot sleep - * @data: first argument of the iterator function - */ -void ieee80211_iterate_stations(struct ieee80211_hw *hw, - void (*iterator)(void *data, - struct ieee80211_sta *sta), - void *data); - -/** * ieee80211_iterate_stations_atomic - iterate stations * * This function iterates over all stations associated with a given @@ -7191,7 +7210,7 @@ ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /** - * ieeee80211_obss_color_collision_notify - notify userland about a BSS color + * ieee80211_obss_color_collision_notify - notify userland about a BSS color * collision. * * @vif: &struct ieee80211_vif pointer from the add_interface callback. @@ -7200,8 +7219,8 @@ ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw, * @gfp: allocation flags */ void -ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, - u64 color_bitmap, gfp_t gfp); +ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif, + u64 color_bitmap, gfp_t gfp); /** * ieee80211_is_tx_data - check if frame is a data frame diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c14a91bbca7c..8ecb0fbee721 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -424,7 +424,8 @@ * interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC * or, if no MAC address given, all stations, on the interface identified - * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and + * by %NL80211_ATTR_IFINDEX. For MLD station, MLD address is used in + * %NL80211_ATTR_MAC. %NL80211_ATTR_MGMT_SUBTYPE and * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type * of disconnection indication should be sent to the station * (Deauthentication or Disassociation frame and reason code for that @@ -5869,6 +5870,7 @@ enum plink_actions { #define NL80211_KEK_LEN 16 #define NL80211_KCK_EXT_LEN 24 #define NL80211_KEK_EXT_LEN 32 +#define NL80211_KCK_EXT_LEN_32 32 #define NL80211_REPLAY_CTR_LEN 8 /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 672eff6f5d32..f5d43f42f6d8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1252,6 +1252,21 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, prev_beacon_int = link_conf->beacon_int; link_conf->beacon_int = params->beacon_interval; + if (params->vht_cap) { + link_conf->vht_su_beamformer = + params->vht_cap->vht_cap_info & + cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); + link_conf->vht_su_beamformee = + params->vht_cap->vht_cap_info & + cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); + link_conf->vht_mu_beamformer = + params->vht_cap->vht_cap_info & + cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); + link_conf->vht_mu_beamformee = + params->vht_cap->vht_cap_info & + cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); + } + if (params->he_cap && params->he_oper) { link_conf->he_support = true; link_conf->htc_trig_based_pkt_ext = @@ -1266,6 +1281,21 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, changed |= BSS_CHANGED_HE_BSS_COLOR; } + if (params->he_cap) { + link_conf->he_su_beamformer = + params->he_cap->phy_cap_info[3] & + IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; + link_conf->he_su_beamformee = + params->he_cap->phy_cap_info[4] & + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE; + link_conf->he_mu_beamformer = + params->he_cap->phy_cap_info[4] & + IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; + link_conf->he_full_ul_mumimo = + params->he_cap->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO; + } + if (sdata->vif.type == NL80211_IFTYPE_AP && params->mbssid_config.tx_wdev) { err = ieee80211_set_ap_mbssid_options(sdata, @@ -2734,7 +2764,7 @@ static int ieee80211_scan(struct wiphy *wiphy, * If the scan has been forced (and the driver supports * forcing), don't care about being beaconing already. * This will create problems to the attached stations (e.g. all - * the frames sent while scanning on other channel will be + * the frames sent while scanning on other channel will be * lost) */ if (sdata->deflink.u.ap.beacon && @@ -4632,7 +4662,7 @@ void ieee80211_color_change_finish(struct ieee80211_vif *vif) EXPORT_SYMBOL_GPL(ieee80211_color_change_finish); void -ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, +ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif, u64 color_bitmap, gfp_t gfp) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -4642,7 +4672,7 @@ ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap, gfp); } -EXPORT_SYMBOL_GPL(ieeee80211_obss_color_collision_notify); +EXPORT_SYMBOL_GPL(ieee80211_obss_color_collision_notify); static int ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c6562a6d2503..e284897ba5e9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3219,9 +3219,9 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) color = le32_get_bits(he_oper->he_oper_params, IEEE80211_HE_OPERATION_BSS_COLOR_MASK); if (color == bss_conf->he_bss_color.color) - ieeee80211_obss_color_collision_notify(&rx->sdata->vif, - BIT_ULL(color), - GFP_ATOMIC); + ieee80211_obss_color_collision_notify(&rx->sdata->vif, + BIT_ULL(color), + GFP_ATOMIC); } } @@ -5194,6 +5194,15 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, status->rate_idx, status->nss)) goto drop; break; + case RX_ENC_EHT: + if (WARN_ONCE(status->rate_idx > 15 || + !status->nss || + status->nss > 8 || + status->eht.gi > NL80211_RATE_INFO_EHT_GI_3_2, + "Rate marked as an EHT rate but data is invalid: MCS:%d, NSS:%d, GI:%d\n", + status->rate_idx, status->nss, status->eht.gi)) + goto drop; + break; default: WARN_ON_ONCE(1); fallthrough; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 04e0f132b1d9..27c737fe7fb8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -4,7 +4,7 @@ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include <linux/module.h> @@ -2406,6 +2406,13 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate, rinfo->he_ru_alloc = STA_STATS_GET(HE_RU, rate); rinfo->he_dcm = STA_STATS_GET(HE_DCM, rate); break; + case STA_STATS_RATE_TYPE_EHT: + rinfo->flags = RATE_INFO_FLAGS_EHT_MCS; + rinfo->mcs = STA_STATS_GET(EHT_MCS, rate); + rinfo->nss = STA_STATS_GET(EHT_NSS, rate); + rinfo->eht_gi = STA_STATS_GET(EHT_GI, rate); + rinfo->eht_ru_alloc = STA_STATS_GET(EHT_RU, rate); + break; } } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 69820b551668..c30f02874fb1 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -936,6 +936,7 @@ enum sta_stats_type { STA_STATS_RATE_TYPE_VHT, STA_STATS_RATE_TYPE_HE, STA_STATS_RATE_TYPE_S1G, + STA_STATS_RATE_TYPE_EHT, }; #define STA_STATS_FIELD_HT_MCS GENMASK( 7, 0) @@ -945,12 +946,16 @@ enum sta_stats_type { #define STA_STATS_FIELD_VHT_NSS GENMASK( 7, 4) #define STA_STATS_FIELD_HE_MCS GENMASK( 3, 0) #define STA_STATS_FIELD_HE_NSS GENMASK( 7, 4) -#define STA_STATS_FIELD_BW GENMASK(11, 8) -#define STA_STATS_FIELD_SGI GENMASK(12, 12) -#define STA_STATS_FIELD_TYPE GENMASK(15, 13) -#define STA_STATS_FIELD_HE_RU GENMASK(18, 16) -#define STA_STATS_FIELD_HE_GI GENMASK(20, 19) -#define STA_STATS_FIELD_HE_DCM GENMASK(21, 21) +#define STA_STATS_FIELD_EHT_MCS GENMASK( 3, 0) +#define STA_STATS_FIELD_EHT_NSS GENMASK( 7, 4) +#define STA_STATS_FIELD_BW GENMASK(12, 8) +#define STA_STATS_FIELD_SGI GENMASK(13, 13) +#define STA_STATS_FIELD_TYPE GENMASK(16, 14) +#define STA_STATS_FIELD_HE_RU GENMASK(19, 17) +#define STA_STATS_FIELD_HE_GI GENMASK(21, 20) +#define STA_STATS_FIELD_HE_DCM GENMASK(22, 22) +#define STA_STATS_FIELD_EHT_RU GENMASK(20, 17) +#define STA_STATS_FIELD_EHT_GI GENMASK(22, 21) #define STA_STATS_FIELD(_n, _v) FIELD_PREP(STA_STATS_FIELD_ ## _n, _v) #define STA_STATS_GET(_n, _v) FIELD_GET(STA_STATS_FIELD_ ## _n, _v) @@ -989,6 +994,13 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s) r |= STA_STATS_FIELD(HE_RU, s->he_ru); r |= STA_STATS_FIELD(HE_DCM, s->he_dcm); break; + case RX_ENC_EHT: + r |= STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_EHT); + r |= STA_STATS_FIELD(EHT_NSS, s->nss); + r |= STA_STATS_FIELD(EHT_MCS, s->rate_idx); + r |= STA_STATS_FIELD(EHT_GI, s->eht.gi); + r |= STA_STATS_FIELD(EHT_RU, s->eht.ru); + break; default: WARN_ON(1); return STA_STATS_RATE_INVALID; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 261ac667887f..1a28fe5cb614 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -832,19 +832,6 @@ static void __iterate_stations(struct ieee80211_local *local, } } -void ieee80211_iterate_stations(struct ieee80211_hw *hw, - void (*iterator)(void *data, - struct ieee80211_sta *sta), - void *data) -{ - struct ieee80211_local *local = hw_to_local(hw); - - mutex_lock(&local->sta_mtx); - __iterate_stations(local, iterator, data); - mutex_unlock(&local->sta_mtx); -} -EXPORT_SYMBOL_GPL(ieee80211_iterate_stations); - void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw, void (*iterator)(void *data, struct ieee80211_sta *sta), @@ -4033,6 +4020,19 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, /* Fill cfg80211 rate info */ switch (status->encoding) { + case RX_ENC_EHT: + ri.flags |= RATE_INFO_FLAGS_EHT_MCS; + ri.mcs = status->rate_idx; + ri.nss = status->nss; + ri.eht_ru_alloc = status->eht.ru; + if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) + ri.flags |= RATE_INFO_FLAGS_SHORT_GI; + /* TODO/FIXME: is this right? handle other PPDUs */ + if (status->flag & RX_FLAG_MACTIME_PLCP_START) { + mpdu_offset += 2; + ts += 36; + } + break; case RX_ENC_HE: ri.flags |= RATE_INFO_FLAGS_HE_MCS; ri.mcs = status->rate_idx; diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index f5afc9bcdee6..786dbfdad772 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -75,6 +75,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev) { struct rfkill_gpio_data *rfkill; struct gpio_desc *gpio; + const char *name_property; + const char *type_property; const char *type_name; int ret; @@ -82,8 +84,15 @@ static int rfkill_gpio_probe(struct platform_device *pdev) if (!rfkill) return -ENOMEM; - device_property_read_string(&pdev->dev, "name", &rfkill->name); - device_property_read_string(&pdev->dev, "type", &type_name); + if (dev_of_node(&pdev->dev)) { + name_property = "label"; + type_property = "radio-type"; + } else { + name_property = "name"; + type_property = "type"; + } + device_property_read_string(&pdev->dev, name_property, &rfkill->name); + device_property_read_string(&pdev->dev, type_property, &type_name); if (!rfkill->name) rfkill->name = dev_name(&pdev->dev); @@ -157,12 +166,19 @@ static const struct acpi_device_id rfkill_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rfkill_acpi_match); #endif +static const struct of_device_id rfkill_of_match[] __maybe_unused = { + { .compatible = "rfkill-gpio", }, + { }, +}; +MODULE_DEVICE_TABLE(of, rfkill_of_match); + static struct platform_driver rfkill_gpio_driver = { .probe = rfkill_gpio_probe, .remove = rfkill_gpio_remove, .driver = { .name = "rfkill_gpio", .acpi_match_table = ACPI_PTR(rfkill_acpi_match), + .of_match_table = of_match_ptr(rfkill_of_match), }, }; diff --git a/net/wireless/core.h b/net/wireless/core.h index af85d8909935..7c61752f6d83 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -278,8 +278,8 @@ struct cfg80211_event { }; struct cfg80211_cached_keys { - struct key_params params[CFG80211_MAX_WEP_KEYS]; - u8 data[CFG80211_MAX_WEP_KEYS][WLAN_KEY_LEN_WEP104]; + struct key_params params[4]; + u8 data[4][WLAN_KEY_LEN_WEP104]; int def; }; diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index edd062f104f4..e6fdb0b8187d 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -45,8 +45,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, cfg80211_hold_bss(bss_from_pub(bss)); wdev->u.ibss.current_bss = bss_from_pub(bss); - if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) - cfg80211_upload_connect_keys(wdev); + cfg80211_upload_connect_keys(wdev); nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid, GFP_KERNEL); @@ -294,7 +293,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); if (!ck) return -ENOMEM; - for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) + for (i = 0; i < 4; i++) ck->params[i].key = ck->data[i]; } err = __cfg80211_join_ibss(rdev, wdev->netdev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 33a82ecab9d5..64cf6110ce9d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -883,7 +883,7 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { }, [NL80211_REKEY_DATA_KCK] = { .type = NLA_BINARY, - .len = NL80211_KCK_EXT_LEN + .len = NL80211_KCK_EXT_LEN_32 }, [NL80211_REKEY_DATA_REPLAY_CTR] = NLA_POLICY_EXACT_LEN(NL80211_REPLAY_CTR_LEN), [NL80211_REKEY_DATA_AKM] = { .type = NLA_U32 }, @@ -13809,7 +13809,9 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) return -ERANGE; if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN && !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK && - nla_len(tb[NL80211_REKEY_DATA_KEK]) == NL80211_KCK_EXT_LEN)) + nla_len(tb[NL80211_REKEY_DATA_KCK]) == NL80211_KCK_EXT_LEN) && + !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_EXT_KCK_32 && + nla_len(tb[NL80211_REKEY_DATA_KCK]) == NL80211_KCK_EXT_LEN_32)) return -ERANGE; rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 4f3f31244e8b..af65196c916e 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -737,51 +737,9 @@ static bool valid_country(const u8 *data, unsigned int size, } #ifdef CONFIG_CFG80211_REQUIRE_SIGNED_REGDB -static struct key *builtin_regdb_keys; - -static void __init load_keys_from_buffer(const u8 *p, unsigned int buflen) -{ - const u8 *end = p + buflen; - size_t plen; - key_ref_t key; - - while (p < end) { - /* Each cert begins with an ASN.1 SEQUENCE tag and must be more - * than 256 bytes in size. - */ - if (end - p < 4) - goto dodgy_cert; - if (p[0] != 0x30 && - p[1] != 0x82) - goto dodgy_cert; - plen = (p[2] << 8) | p[3]; - plen += 4; - if (plen > end - p) - goto dodgy_cert; - - key = key_create_or_update(make_key_ref(builtin_regdb_keys, 1), - "asymmetric", NULL, p, plen, - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ), - KEY_ALLOC_NOT_IN_QUOTA | - KEY_ALLOC_BUILT_IN | - KEY_ALLOC_BYPASS_RESTRICTION); - if (IS_ERR(key)) { - pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", - PTR_ERR(key)); - } else { - pr_notice("Loaded X.509 cert '%s'\n", - key_ref_to_ptr(key)->description); - key_ref_put(key); - } - p += plen; - } - - return; +#include <keys/asymmetric-type.h> -dodgy_cert: - pr_err("Problem parsing in-kernel X.509 certificate list\n"); -} +static struct key *builtin_regdb_keys; static int __init load_builtin_regdb_keys(void) { @@ -797,11 +755,15 @@ static int __init load_builtin_regdb_keys(void) pr_notice("Loading compiled-in X.509 certificates for regulatory database\n"); #ifdef CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS - load_keys_from_buffer(shipped_regdb_certs, shipped_regdb_certs_len); + x509_load_certificate_list(shipped_regdb_certs, + shipped_regdb_certs_len, + builtin_regdb_keys); #endif #ifdef CONFIG_CFG80211_EXTRA_REGDB_KEYDIR if (CONFIG_CFG80211_EXTRA_REGDB_KEYDIR[0] != '\0') - load_keys_from_buffer(extra_regdb_certs, extra_regdb_certs_len); + x509_load_certificate_list(extra_regdb_certs, + extra_regdb_certs_len, + builtin_regdb_keys); #endif return 0; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 4b5b6ee0fe01..123248b2c0be 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -855,8 +855,7 @@ void __cfg80211_connect_result(struct net_device *dev, ETH_ALEN); } - if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) - cfg80211_upload_connect_keys(wdev); + cfg80211_upload_connect_keys(wdev); rcu_read_lock(); for_each_valid_link(cr, link) { @@ -1462,9 +1461,6 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, connect->crypto.ciphers_pairwise[0] = cipher; } } - - connect->crypto.wep_keys = connkeys->params; - connect->crypto.wep_tx_key = connkeys->def; } else { if (WARN_ON(connkeys)) return -EINVAL; diff --git a/net/wireless/util.c b/net/wireless/util.c index 8f403f9fe816..38d3b434c18c 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -934,7 +934,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) if (!wdev->connect_keys) return; - for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) { + for (i = 0; i < 4; i++) { if (!wdev->connect_keys->params[i].cipher) continue; if (rdev_add_key(rdev, dev, -1, i, false, NULL, diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 8a24dfca75af..e3acfac7430a 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -439,7 +439,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, GFP_KERNEL); if (!wdev->wext.keys) return -ENOMEM; - for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) + for (i = 0; i < 4; i++) wdev->wext.keys->params[i].key = wdev->wext.keys->data[i]; } diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index fe8765c4075d..13a72b17248e 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -636,7 +636,15 @@ void wireless_send_event(struct net_device * dev, } EXPORT_SYMBOL(wireless_send_event); +#ifdef CONFIG_CFG80211_WEXT +static void wireless_warn_cfg80211_wext(void) +{ + char name[sizeof(current->comm)]; + pr_warn_ratelimited("warning: `%s' uses wireless extensions that are deprecated for modern drivers; use nl80211\n", + get_task_comm(name, current)); +} +#endif /* IW handlers */ @@ -652,8 +660,12 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev) if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy && dev->ieee80211_ptr->wiphy->wext && - dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) + dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) { + wireless_warn_cfg80211_wext(); + if (dev->ieee80211_ptr->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO) + return NULL; return dev->ieee80211_ptr->wiphy->wext->get_wireless_stats(dev); + } #endif /* not found */ @@ -690,8 +702,12 @@ static iw_handler get_handler(struct net_device *dev, unsigned int cmd) const struct iw_handler_def *handlers = NULL; #ifdef CONFIG_CFG80211_WEXT - if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy) + if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy) { + wireless_warn_cfg80211_wext(); + if (dev->ieee80211_ptr->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO) + return NULL; handlers = dev->ieee80211_ptr->wiphy->wext; + } #endif #ifdef CONFIG_WIRELESS_EXT if (dev->wireless_handlers) diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 191c6d98c700..f231207ca210 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -47,7 +47,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); if (!ck) return -ENOMEM; - for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) + for (i = 0; i < 4; i++) ck->params[i].key = ck->data[i]; } |