wireless-drivers-next patches for v5.5

Last set of patches for v5.5. Major features here 802.11ax support for
 qtnfmac and airtime fairness support to mt76. And naturally smaller
 fixes and improvements all over.
 
 Major changes:
 
 qtnfmac
 
 * add 802.11ax support in AP mode
 
 * enable offload bridging support
 
 iwlwifi
 
 * support TX/RX antennas reporting
 
 mt76
 
 * mt7615 smart carrier sense support
 
 * aggregation statistics via debugfs
 
 * airtime fairness (ATF) support
 
 * mt76x0 OF mac address support
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJd2CicAAoJEG4XJFUm622beBYH/2zUMDpBWe10MPKB8l1Xu7k2
 LkC9f89ex+EIXoh6Uun12VE3oQZG8/zinKJ5llqGqLtsNoay1gWHLydlg8VfmuaO
 8oN8vpanKj4ofk1jwS8nqKz8B36SwhJMZEF5lX35YNQx7a4lK0geu3wNy8D5jiwh
 8S8uBdJnHsKd/b2vBc2y/WKdyuYJhrIQleyPo7hBBQIT6CsJYLWT0LT3uA7kWmXG
 gKEz/+Q92IjnE8vRbmCmvfOM5DYZbxLCRR3lebaXO/heac40bWi3JfeLFMTZR9aM
 +VZtpbuvOzlAPpHlGnswKs4NlVbpUl01ST0IEEwu27W4DkFSdtnTzJIaXL1hIyk=
 =1tfL
 -----END PGP SIGNATURE-----

Merge tag 'wireless-drivers-next-2019-11-22' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next

Kalle Valo says:

====================
wireless-drivers-next patches for v5.5

Last set of patches for v5.5. Major features here 802.11ax support for
qtnfmac and airtime fairness support to mt76. And naturally smaller
fixes and improvements all over.

Major changes:

qtnfmac

* add 802.11ax support in AP mode

* enable offload bridging support

iwlwifi

* support TX/RX antennas reporting

mt76

* mt7615 smart carrier sense support

* aggregation statistics via debugfs

* airtime fairness (ATF) support

* mt76x0 OF mac address support
====================

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
This commit is contained in:
Jakub Kicinski 2019-11-23 12:00:54 -08:00
commit 3a06ee3396
96 changed files with 2255 additions and 565 deletions

View File

@ -778,7 +778,6 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr,
{
u8 desc;
u32 val, szdesc;
u8 mpnum = 0;
u8 stype, sztype, wraptype;
*regbase = 0;
@ -786,7 +785,6 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr,
val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc);
if (desc == DMP_DESC_MASTER_PORT) {
mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S;
wraptype = DMP_SLAVE_TYPE_MWRAP;
} else if (desc == DMP_DESC_ADDRESS) {
/* revert erom address */
@ -854,7 +852,7 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci)
u8 desc_type = 0;
u32 val;
u16 id;
u8 nmp, nsp, nmw, nsw, rev;
u8 nmw, nsw, rev;
u32 base, wrap;
int err;
@ -880,8 +878,6 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci)
return -EFAULT;
/* only look at cores with master port(s) */
nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S;
nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S;
nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S;
nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S;
rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;

View File

@ -1350,6 +1350,11 @@ void brcmf_detach(struct device *dev)
brcmf_fweh_detach(drvr);
brcmf_proto_detach(drvr);
if (drvr->mon_if) {
brcmf_net_detach(drvr->mon_if->ndev, false);
drvr->mon_if = NULL;
}
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS - 1; i > -1; i--) {
if (drvr->iflist[i])

View File

@ -1425,6 +1425,8 @@ static int brcmf_pcie_reset(struct device *dev)
struct brcmf_fw_request *fwreq;
int err;
brcmf_pcie_intr_disable(devinfo);
brcmf_pcie_bus_console_read(devinfo, true);
brcmf_detach(dev);

View File

@ -5565,7 +5565,7 @@ static void shim__set_security(struct net_device *dev,
struct libipw_security *sec)
{
struct ipw2100_priv *priv = libipw_priv(dev);
int i, force_update = 0;
int i;
mutex_lock(&priv->action_mutex);
if (!(priv->status & STATUS_INITIALIZED))
@ -5605,7 +5605,6 @@ static void shim__set_security(struct net_device *dev,
priv->ieee->sec.flags |= SEC_ENABLED;
priv->ieee->sec.enabled = sec->enabled;
priv->status |= STATUS_SECURITY_UPDATED;
force_update = 1;
}
if (sec->flags & SEC_ENCRYPT)

View File

@ -6788,9 +6788,6 @@ static int ipw_wx_set_mlme(struct net_device *dev,
{
struct ipw_priv *priv = libipw_priv(dev);
struct iw_mlme *mlme = (struct iw_mlme *)extra;
__le16 reason;
reason = cpu_to_le16(mlme->reason_code);
switch (mlme->cmd) {
case IW_MLME_DEAUTH:

View File

@ -57,7 +57,7 @@
#include "iwl-prph.h"
/* Highest firmware API version supported */
#define IWL_22000_UCODE_API_MAX 51
#define IWL_22000_UCODE_API_MAX 52
/* Lowest firmware API version supported */
#define IWL_22000_UCODE_API_MIN 39

View File

@ -171,6 +171,9 @@ void iwl_leds_init(struct iwl_priv *priv)
priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
wiphy_name(priv->hw->wiphy));
if (!priv->led.name)
return;
priv->led.brightness_set = iwl_led_brightness_set;
priv->led.blink_set = iwl_led_blink_set;
priv->led.max_brightness = 1;

View File

@ -851,7 +851,7 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
* Is there a need to switch between
* full concurrency and 3-wire?
*/
if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
if (priv->bt_ci_compliance)
full_concurrent = true;
else
full_concurrent = false;

View File

@ -664,6 +664,9 @@ enum iwl_umac_scan_general_flags2 {
* @IWL_UMAC_SCAN_GEN_FLAGS_V2_MULTI_SSID: matching on multiple SSIDs
* @IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE: all the channels scanned
* as passive
* @IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN: at the end of 2.4GHz and
* 5.2Ghz bands scan, trigger scan on 6GHz band to discover
* the reported collocated APs
*/
enum iwl_umac_scan_general_flags_v2 {
IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC = BIT(0),
@ -678,6 +681,7 @@ enum iwl_umac_scan_general_flags_v2 {
IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START = BIT(9),
IWL_UMAC_SCAN_GEN_FLAGS_V2_MULTI_SSID = BIT(10),
IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE = BIT(11),
IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN = BIT(12),
};
/**
@ -893,7 +897,27 @@ struct iwl_scan_probe_params_v3 {
struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
__le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE];
u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE];
} __packed;
} __packed; /* SCAN_PROBE_PARAMS_API_S_VER_3 */
/**
* struct iwl_scan_probe_params_v4
* @preq: scan probe request params
* @short_ssid_num: number of valid short SSIDs in short ssid array
* @bssid_num: number of valid bssid in bssids array
* @reserved: reserved
* @direct_scan: list of ssids
* @short_ssid: array of short ssids
* @bssid_array: array of bssids
*/
struct iwl_scan_probe_params_v4 {
struct iwl_scan_probe_req preq;
u8 short_ssid_num;
u8 bssid_num;
__le16 reserved;
struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
__le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE];
u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE];
} __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */
#define SCAN_MAX_NUM_CHANS_V3 67
@ -932,8 +956,8 @@ struct iwl_scan_channel_params_v4 {
u8 reserved;
struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3];
u8 adwell_ch_override_bitmap[16];
} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_4 */
} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_4 also
SCAN_CHANNEL_PARAMS_API_S_VER_5 */
/**
* struct iwl_scan_general_params_v10
* @flags: &enum iwl_umac_scan_flags
@ -1014,6 +1038,20 @@ struct iwl_scan_req_params_v12 {
struct iwl_scan_probe_params_v3 probe_params;
} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_12 */
/**
* struct iwl_scan_req_params_v13
* @general_params: &struct iwl_scan_general_params_v10
* @channel_params: &struct iwl_scan_channel_params_v4
* @periodic_params: &struct iwl_scan_periodic_parms_v1
* @probe_params: &struct iwl_scan_probe_params_v4
*/
struct iwl_scan_req_params_v13 {
struct iwl_scan_general_params_v10 general_params;
struct iwl_scan_channel_params_v4 channel_params;
struct iwl_scan_periodic_parms_v1 periodic_params;
struct iwl_scan_probe_params_v4 probe_params;
} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_13 */
/**
* struct iwl_scan_req_umac_v11
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
@ -1038,6 +1076,18 @@ struct iwl_scan_req_umac_v12 {
struct iwl_scan_req_params_v12 scan_params;
} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_12 */
/**
* struct iwl_scan_req_umac_v13
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
* @ooc_priority: out of channel priority - &enum iwl_scan_priority
* @scan_params: scan parameters
*/
struct iwl_scan_req_umac_v13 {
__le32 uid;
__le32 ooc_priority;
struct iwl_scan_req_params_v13 scan_params;
} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_13 */
/**
* struct iwl_umac_scan_abort
* @uid: scan id, &enum iwl_umac_scan_uid_offsets

View File

@ -409,7 +409,6 @@ struct iwl_fw_mon_regs {
* @mac_addr_from_csr: read HW address from CSR registers
* @features: hw features, any combination of feature_whitelist
* @pwr_tx_backoffs: translation table between power limits and backoffs
* @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
* @max_tx_agg_size: max TX aggregation size of the ADDBA request/response
* @max_ht_ampdu_factor: the exponent of the max length of A-MPDU that the
* station can receive in HT
@ -481,7 +480,6 @@ struct iwl_cfg {
u8 valid_rx_ant;
u8 non_shared_ant;
u8 nvm_hw_section_num;
u8 max_rx_agg_size;
u8 max_tx_agg_size;
u8 max_ht_ampdu_exponent;
u8 max_vht_ampdu_exponent;

View File

@ -3,7 +3,7 @@
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Deutschland GmbH
* Copyright(c) 2018 Intel Corporation
* Copyright(c) 2018 - 2019 Intel Corporation
*
* Contact Information:
* Intel Linux Wireless <linuxwifi@intel.com>
@ -21,16 +21,18 @@
TRACE_EVENT(iwlwifi_dev_tx_tb,
TP_PROTO(const struct device *dev, struct sk_buff *skb,
u8 *data_src, size_t data_len),
TP_ARGS(dev, skb, data_src, data_len),
u8 *data_src, dma_addr_t phys, size_t data_len),
TP_ARGS(dev, skb, data_src, phys, data_len),
TP_STRUCT__entry(
DEV_ENTRY
__field(u64, phys)
__dynamic_array(u8, data,
iwl_trace_data(skb) ? data_len : 0)
),
TP_fast_assign(
DEV_ASSIGN;
__entry->phys = phys;
if (iwl_trace_data(skb))
memcpy(__get_dynamic_array(data), data_src, data_len);
),

View File

@ -129,6 +129,9 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",
wiphy_name(mvm->hw->wiphy));
if (!mvm->led.name)
return -ENOMEM;
mvm->led.brightness_set = iwl_led_brightness_set;
mvm->led.max_brightness = 1;

View File

@ -355,6 +355,15 @@ static const struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = {
},
};
static int
iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
*tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
*rx_ant = iwl_mvm_get_valid_rx_ant(mvm);
return 0;
}
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
{
struct ieee80211_hw *hw = mvm->hw;
@ -734,6 +743,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
hw->wiphy->available_antennas_tx = iwl_mvm_get_valid_tx_ant(mvm);
hw->wiphy->available_antennas_rx = iwl_mvm_get_valid_rx_ant(mvm);
ret = ieee80211_register_hw(mvm->hw);
if (ret) {
iwl_mvm_leds_exit(mvm);
@ -5028,6 +5040,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
.ampdu_action = iwl_mvm_mac_ampdu_action,
.get_antenna = iwl_mvm_op_get_antenna,
.start = iwl_mvm_mac_start,
.reconfig_complete = iwl_mvm_mac_reconfig_complete,
.stop = iwl_mvm_mac_stop,

View File

@ -664,10 +664,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (!hw)
return NULL;
if (cfg->max_rx_agg_size)
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
else
hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
if (cfg->max_tx_agg_size)
hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;

View File

@ -370,8 +370,6 @@ static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm,
if (dtimper >= 10)
return;
/* TODO: check that multicast wake lock is off */
if (host_awake) {
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_LP)
return;

View File

@ -23,7 +23,7 @@
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Linux Wireless <linuxwifi@intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE

View File

@ -1897,6 +1897,15 @@ iwl_mvm_scan_umac_fill_probe_p_v3(struct iwl_mvm_scan_params *params,
iwl_scan_build_ssids(params, pp->direct_scan, NULL);
}
static void
iwl_mvm_scan_umac_fill_probe_p_v4(struct iwl_mvm_scan_params *params,
struct iwl_scan_probe_params_v4 *pp,
u32 *bitmap_ssid)
{
pp->preq = params->preq;
iwl_scan_build_ssids(params, pp->direct_scan, bitmap_ssid);
}
static void
iwl_mvm_scan_umac_fill_ch_p_v3(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
@ -1915,14 +1924,17 @@ static void
iwl_mvm_scan_umac_fill_ch_p_v4(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
struct ieee80211_vif *vif,
struct iwl_scan_channel_params_v4 *cp)
struct iwl_scan_channel_params_v4 *cp,
u32 channel_cfg_flags)
{
cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif);
cp->count = params->n_channels;
cp->num_of_aps_override = IWL_SCAN_ADWELL_DEFAULT_N_APS_OVERRIDE;
iwl_mvm_umac_scan_cfg_channels_v4(mvm, params->channels, cp,
params->n_channels, 0, vif->type);
params->n_channels,
channel_cfg_flags,
vif->type);
}
static int iwl_mvm_scan_umac_v11(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@ -1984,7 +1996,41 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_scan_umac_fill_probe_p_v3(params, &scan_p->probe_params);
iwl_mvm_scan_umac_fill_ch_p_v4(mvm, params, vif,
&scan_p->channel_params);
&scan_p->channel_params, 0);
return 0;
}
static int iwl_mvm_scan_umac_v13(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_scan_params *params, int type,
int uid)
{
struct iwl_scan_req_umac_v13 *cmd = mvm->scan_cmd;
struct iwl_scan_req_params_v13 *scan_p = &cmd->scan_params;
int ret;
u16 gen_flags;
u32 bitmap_ssid = 0;
mvm->scan_uid_status[uid] = type;
cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params));
cmd->uid = cpu_to_le32(uid);
gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type);
iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif,
&scan_p->general_params,
gen_flags);
ret = iwl_mvm_fill_scan_sched_params(params,
scan_p->periodic_params.schedule,
&scan_p->periodic_params.delay);
if (ret)
return ret;
iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params,
&bitmap_ssid);
iwl_mvm_scan_umac_fill_ch_p_v4(mvm, params, vif,
&scan_p->channel_params, bitmap_ssid);
return 0;
}
@ -2104,6 +2150,7 @@ struct iwl_scan_umac_handler {
static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = {
/* set the newest version first to shorten the list traverse time */
IWL_SCAN_UMAC_HANDLER(13),
IWL_SCAN_UMAC_HANDLER(12),
IWL_SCAN_UMAC_HANDLER(11),
};
@ -2462,6 +2509,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
static int iwl_scan_req_umac_get_size(u8 scan_ver)
{
switch (scan_ver) {
IWL_SCAN_REQ_UMAC_HANDLE_SIZE(13);
IWL_SCAN_REQ_UMAC_HANDLE_SIZE(12);
IWL_SCAN_REQ_UMAC_HANDLE_SIZE(11);
}

View File

@ -646,7 +646,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
/*****************************************************
* RX
******************************************************/
int _iwl_pcie_rx_init(struct iwl_trans *trans);
int iwl_pcie_rx_init(struct iwl_trans *trans);
int iwl_pcie_gen2_rx_init(struct iwl_trans *trans);
irqreturn_t iwl_pcie_msix_isr(int irq, void *data);
@ -660,7 +659,6 @@ void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq);
int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget);
void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority,
struct iwl_rxq *rxq);
int iwl_pcie_rx_alloc(struct iwl_trans *trans);
/*****************************************************
* ICT - interrupt handling

View File

@ -322,7 +322,7 @@ static void iwl_pcie_rxmq_restock(struct iwl_trans *trans,
WARN_ON(rxb->page_dma & DMA_BIT_MASK(12));
/* Point to Rx buffer via next RBD in circular buffer */
iwl_pcie_restock_bd(trans, rxq, rxb);
rxq->write = (rxq->write + 1) & MQ_RX_TABLE_MASK;
rxq->write = (rxq->write + 1) & (rxq->queue_size - 1);
rxq->free_count--;
}
spin_unlock(&rxq->lock);
@ -793,7 +793,7 @@ err:
return -ENOMEM;
}
int iwl_pcie_rx_alloc(struct iwl_trans *trans)
static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rb_allocator *rba = &trans_pcie->rba;
@ -1024,7 +1024,7 @@ int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget)
return 0;
}
int _iwl_pcie_rx_init(struct iwl_trans *trans)
static int _iwl_pcie_rx_init(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *def_rxq;

View File

@ -333,7 +333,8 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans,
goto out_err;
}
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len);
trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, tb_len);
trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr,
tb_phys, tb_len);
/* add this subframe's headers' length to the tx_cmd */
le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start);
@ -351,7 +352,7 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans,
}
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len);
trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data,
tb_len);
tb_phys, tb_len);
data_left -= tb_len;
tso_build_data(skb, &tso, tb_len);
@ -441,9 +442,8 @@ static int iwl_pcie_gen2_tx_add_frags(struct iwl_trans *trans,
return -ENOMEM;
tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys,
skb_frag_size(frag));
trace_iwlwifi_dev_tx_tb(trans->dev, skb,
skb_frag_address(frag),
skb_frag_size(frag));
trace_iwlwifi_dev_tx_tb(trans->dev, skb, skb_frag_address(frag),
tb_phys, skb_frag_size(frag));
if (tb_idx < 0)
return tb_idx;
@ -468,6 +468,7 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans,
dma_addr_t tb_phys;
int len, tb1_len, tb2_len;
void *tb1_addr;
struct sk_buff *frag;
tb_phys = iwl_pcie_get_first_tb_dma(txq, idx);
@ -508,14 +509,25 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans,
if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
goto out_err;
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb2_len);
trace_iwlwifi_dev_tx_tb(trans->dev, skb,
skb->data + hdr_len,
tb2_len);
trace_iwlwifi_dev_tx_tb(trans->dev, skb, skb->data + hdr_len,
tb_phys, tb2_len);
}
if (iwl_pcie_gen2_tx_add_frags(trans, skb, tfd, out_meta))
goto out_err;
skb_walk_frags(skb, frag) {
tb_phys = dma_map_single(trans->dev, frag->data,
skb_headlen(frag), DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
goto out_err;
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, skb_headlen(frag));
trace_iwlwifi_dev_tx_tb(trans->dev, skb, frag->data,
tb_phys, skb_headlen(frag));
if (iwl_pcie_gen2_tx_add_frags(trans, frag, tfd, out_meta))
goto out_err;
}
return tfd;
out_err:

View File

@ -2019,9 +2019,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
head_tb_len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
return -EINVAL;
trace_iwlwifi_dev_tx_tb(trans->dev, skb,
skb->data + hdr_len,
head_tb_len);
trace_iwlwifi_dev_tx_tb(trans->dev, skb, skb->data + hdr_len,
tb_phys, head_tb_len);
iwl_pcie_txq_build_tfd(trans, txq, tb_phys, head_tb_len, false);
}
@ -2039,9 +2038,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
return -EINVAL;
trace_iwlwifi_dev_tx_tb(trans->dev, skb,
skb_frag_address(frag),
skb_frag_size(frag));
trace_iwlwifi_dev_tx_tb(trans->dev, skb, skb_frag_address(frag),
tb_phys, skb_frag_size(frag));
tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys,
skb_frag_size(frag), false);
if (tb_idx < 0)
@ -2222,7 +2220,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
iwl_pcie_txq_build_tfd(trans, txq, hdr_tb_phys,
hdr_tb_len, false);
trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr,
hdr_tb_len);
hdr_tb_phys, hdr_tb_len);
/* add this subframe's headers' length to the tx_cmd */
le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start);
@ -2248,7 +2246,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
iwl_pcie_txq_build_tfd(trans, txq, tb_phys,
size, false);
trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data,
size);
tb_phys, size);
data_left -= size;
tso_build_data(skb, &tso, size);

View File

@ -6,7 +6,7 @@ obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o
mt76-y := \
mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
tx.o agg-rx.o mcu.o
tx.o agg-rx.o mcu.o airtime.o
mt76-$(CONFIG_PCI) += pci.o

View File

@ -130,8 +130,10 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
return;
spin_lock_bh(&tid->lock);
mt76_rx_aggr_release_frames(tid, frames, seqno);
mt76_rx_aggr_release_head(tid, frames);
if (!tid->stopped) {
mt76_rx_aggr_release_frames(tid, frames, seqno);
mt76_rx_aggr_release_head(tid, frames);
}
spin_unlock_bh(&tid->lock);
}
@ -257,8 +259,6 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid)
u8 size = tid->size;
int i;
cancel_delayed_work(&tid->reorder_work);
spin_lock_bh(&tid->lock);
tid->stopped = true;
@ -273,21 +273,19 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid)
}
spin_unlock_bh(&tid->lock);
cancel_delayed_work_sync(&tid->reorder_work);
}
void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno)
{
struct mt76_rx_tid *tid;
struct mt76_rx_tid *tid = NULL;
rcu_read_lock();
tid = rcu_dereference(wcid->aggr[tidno]);
rcu_swap_protected(wcid->aggr[tidno], tid,
lockdep_is_held(&dev->mutex));
if (tid) {
rcu_assign_pointer(wcid->aggr[tidno], NULL);
mt76_rx_aggr_shutdown(dev, tid);
kfree_rcu(tid, rcu_head);
}
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop);

View File

@ -0,0 +1,326 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (C) 2019 Felix Fietkau <nbd@nbd.name>
*/
#include "mt76.h"
#define AVG_PKT_SIZE 1024
/* Number of bits for an average sized packet */
#define MCS_NBITS (AVG_PKT_SIZE << 3)
/* Number of symbols for a packet with (bps) bits per symbol */
#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps))
/* Transmission time (1024 usec) for a packet containing (syms) * symbols */
#define MCS_SYMBOL_TIME(sgi, syms) \
(sgi ? \
((syms) * 18 * 1024 + 4 * 1024) / 5 : /* syms * 3.6 us */ \
((syms) * 1024) << 2 /* syms * 4 us */ \
)
/* Transmit duration for the raw data part of an average sized packet */
#define MCS_DURATION(streams, sgi, bps) \
MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
#define BW_20 0
#define BW_40 1
#define BW_80 2
/*
* Define group sort order: HT40 -> SGI -> #streams
*/
#define MT_MAX_STREAMS 4
#define MT_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
#define MT_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */
#define MT_HT_GROUPS_NB (MT_MAX_STREAMS * \
MT_HT_STREAM_GROUPS)
#define MT_VHT_GROUPS_NB (MT_MAX_STREAMS * \
MT_VHT_STREAM_GROUPS)
#define MT_GROUPS_NB (MT_HT_GROUPS_NB + \
MT_VHT_GROUPS_NB)
#define MT_HT_GROUP_0 0
#define MT_VHT_GROUP_0 (MT_HT_GROUP_0 + MT_HT_GROUPS_NB)
#define MCS_GROUP_RATES 10
#define HT_GROUP_IDX(_streams, _sgi, _ht40) \
MT_HT_GROUP_0 + \
MT_MAX_STREAMS * 2 * _ht40 + \
MT_MAX_STREAMS * _sgi + \
_streams - 1
#define _MAX(a, b) (((a)>(b))?(a):(b))
#define GROUP_SHIFT(duration) \
_MAX(0, 16 - __builtin_clz(duration))
/* MCS rate information for an MCS group */
#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \
[HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \
.shift = _s, \
.duration = { \
MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s, \
MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s, \
MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s, \
MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s, \
MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s, \
MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s, \
MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s, \
MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s \
} \
}
#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \
GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26))
#define MCS_GROUP(_streams, _sgi, _ht40) \
__MCS_GROUP(_streams, _sgi, _ht40, \
MCS_GROUP_SHIFT(_streams, _sgi, _ht40))
#define VHT_GROUP_IDX(_streams, _sgi, _bw) \
(MT_VHT_GROUP_0 + \
MT_MAX_STREAMS * 2 * (_bw) + \
MT_MAX_STREAMS * (_sgi) + \
(_streams) - 1)
#define BW2VBPS(_bw, r3, r2, r1) \
(_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
#define __VHT_GROUP(_streams, _sgi, _bw, _s) \
[VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
.shift = _s, \
.duration = { \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 117, 54, 26)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 234, 108, 52)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 351, 162, 78)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 468, 216, 104)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 702, 324, 156)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 936, 432, 208)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 1053, 486, 234)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 1170, 540, 260)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 1404, 648, 312)) >> _s, \
MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 1560, 720, 346)) >> _s \
} \
}
#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \
GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 117, 54, 26)))
#define VHT_GROUP(_streams, _sgi, _bw) \
__VHT_GROUP(_streams, _sgi, _bw, \
VHT_GROUP_SHIFT(_streams, _sgi, _bw))
struct mcs_group {
u8 shift;
u16 duration[MCS_GROUP_RATES];
};
static const struct mcs_group airtime_mcs_groups[] = {
MCS_GROUP(1, 0, BW_20),
MCS_GROUP(2, 0, BW_20),
MCS_GROUP(3, 0, BW_20),
MCS_GROUP(4, 0, BW_20),
MCS_GROUP(1, 1, BW_20),
MCS_GROUP(2, 1, BW_20),
MCS_GROUP(3, 1, BW_20),
MCS_GROUP(4, 1, BW_20),
MCS_GROUP(1, 0, BW_40),
MCS_GROUP(2, 0, BW_40),
MCS_GROUP(3, 0, BW_40),
MCS_GROUP(4, 0, BW_40),
MCS_GROUP(1, 1, BW_40),
MCS_GROUP(2, 1, BW_40),
MCS_GROUP(3, 1, BW_40),
MCS_GROUP(4, 1, BW_40),
VHT_GROUP(1, 0, BW_20),
VHT_GROUP(2, 0, BW_20),
VHT_GROUP(3, 0, BW_20),
VHT_GROUP(4, 0, BW_20),
VHT_GROUP(1, 1, BW_20),
VHT_GROUP(2, 1, BW_20),
VHT_GROUP(3, 1, BW_20),
VHT_GROUP(4, 1, BW_20),
VHT_GROUP(1, 0, BW_40),
VHT_GROUP(2, 0, BW_40),
VHT_GROUP(3, 0, BW_40),
VHT_GROUP(4, 0, BW_40),
VHT_GROUP(1, 1, BW_40),
VHT_GROUP(2, 1, BW_40),
VHT_GROUP(3, 1, BW_40),
VHT_GROUP(4, 1, BW_40),
VHT_GROUP(1, 0, BW_80),
VHT_GROUP(2, 0, BW_80),
VHT_GROUP(3, 0, BW_80),
VHT_GROUP(4, 0, BW_80),
VHT_GROUP(1, 1, BW_80),
VHT_GROUP(2, 1, BW_80),
VHT_GROUP(3, 1, BW_80),
VHT_GROUP(4, 1, BW_80),
};
static u32
mt76_calc_legacy_rate_duration(const struct ieee80211_rate *rate, bool short_pre,
int len)
{
u32 duration;
switch (rate->hw_value >> 8) {
case MT_PHY_TYPE_CCK:
duration = 144 + 48; /* preamble + PLCP */
if (short_pre)
duration >>= 1;
duration += 10; /* SIFS */
break;
case MT_PHY_TYPE_OFDM:
duration = 20 + 16; /* premable + SIFS */
break;
default:
WARN_ON_ONCE(1);
return 0;
}
len <<= 3;
duration += (len * 10) / rate->bitrate;
return duration;
}
u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status,
int len)
{
struct ieee80211_supported_band *sband;
const struct ieee80211_rate *rate;
bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI;
bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
int bw, streams;
u32 duration;
int group, idx;
switch (status->bw) {
case RATE_INFO_BW_20:
bw = BW_20;
break;
case RATE_INFO_BW_40:
bw = BW_40;
break;
case RATE_INFO_BW_80:
bw = BW_80;
break;
default:
WARN_ON_ONCE(1);
return 0;
}
switch (status->encoding) {
case RX_ENC_LEGACY:
if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
return 0;
sband = dev->hw->wiphy->bands[status->band];
if (!sband || status->rate_idx > sband->n_bitrates)
return 0;
rate = &sband->bitrates[status->rate_idx];
return mt76_calc_legacy_rate_duration(rate, sp, len);
case RX_ENC_VHT:
streams = status->nss;
idx = status->rate_idx;
group = VHT_GROUP_IDX(streams, sgi, bw);
break;
case RX_ENC_HT:
streams = ((status->rate_idx >> 3) & 3) + 1;
idx = status->rate_idx & 7;
group = HT_GROUP_IDX(streams, sgi, bw);
break;
default:
WARN_ON_ONCE(1);
return 0;
}
if (WARN_ON_ONCE(streams > 4))
return 0;
duration = airtime_mcs_groups[group].duration[idx];
duration <<= airtime_mcs_groups[group].shift;
duration *= len;
duration /= AVG_PKT_SIZE;
duration /= 1024;
duration += 36 + (streams << 2);
return duration;
}
u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info,
int len)
{
struct mt76_rx_status stat = {
.band = info->band,
};
u32 duration = 0;
int i;
for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
struct ieee80211_tx_rate *rate = &info->status.rates[i];
u32 cur_duration;
if (rate->idx < 0 || !rate->count)
break;
if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
stat.bw = RATE_INFO_BW_80;
else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
stat.bw = RATE_INFO_BW_40;
else
stat.bw = RATE_INFO_BW_20;
stat.enc_flags = 0;
if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
stat.enc_flags |= RX_ENC_FLAG_SHORTPRE;
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
stat.enc_flags |= RX_ENC_FLAG_SHORT_GI;
stat.rate_idx = rate->idx;
if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
stat.encoding = RX_ENC_VHT;
stat.rate_idx = ieee80211_rate_get_vht_mcs(rate);
stat.nss = ieee80211_rate_get_vht_nss(rate);
} else if (rate->flags & IEEE80211_TX_RC_MCS) {
stat.encoding = RX_ENC_HT;
} else {
stat.encoding = RX_ENC_LEGACY;
}
cur_duration = mt76_calc_rx_airtime(dev, &stat, len);
duration += cur_duration * rate->count;
}
return duration;
}
EXPORT_SYMBOL_GPL(mt76_calc_tx_airtime);

View File

@ -25,8 +25,7 @@ mt76_reg_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set,
"0x%08llx\n");
static int
mt76_queues_read(struct seq_file *s, void *data)
int mt76_queues_read(struct seq_file *s, void *data)
{
struct mt76_dev *dev = dev_get_drvdata(s->private);
int i;
@ -45,6 +44,7 @@ mt76_queues_read(struct seq_file *s, void *data)
return 0;
}
EXPORT_SYMBOL_GPL(mt76_queues_read);
void mt76_seq_puts_array(struct seq_file *file, const char *str,
s8 *val, int len)
@ -90,7 +90,6 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom);
if (dev->otp.data)
debugfs_create_blob("otp", 0400, dir, &dev->otp);
debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read);
debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir,
mt76_read_rate_txpower);

View File

@ -166,7 +166,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
dev->drv->tx_complete_skb(dev, qid, &entry);
if (entry.txwi) {
if (!(dev->drv->txwi_flags & MT_TXWI_NO_FREE))
if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE))
mt76_put_txwi(dev, entry.txwi);
wake = !flush;
}
@ -301,7 +301,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
txwi = mt76_get_txwi_ptr(dev, t);
skb->prev = skb->next = NULL;
if (dev->drv->tx_aligned4_skbs)
if (dev->drv->drv_flags & MT_DRV_TX_ALIGNED4_SKBS)
mt76_insert_hdr_pad(skb);
len = skb_headlen(skb);
@ -365,7 +365,6 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
int frames = 0;
int len = SKB_WITH_OVERHEAD(q->buf_size);
int offset = q->buf_offset;
int idx;
spin_lock_bh(&q->lock);
@ -384,7 +383,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
qbuf.addr = addr + offset;
qbuf.len = len - offset;
idx = mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL);
mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL);
frames++;
}
@ -539,10 +538,8 @@ mt76_dma_rx_poll(struct napi_struct *napi, int budget)
rcu_read_unlock();
if (done < budget) {
napi_complete(napi);
if (done < budget && napi_complete(napi))
dev->drv->rx_poll_complete(dev, qid);
}
return done;
}

View File

@ -105,7 +105,15 @@ static int mt76_led_init(struct mt76_dev *dev)
dev->led_al = of_property_read_bool(np, "led-active-low");
}
return devm_led_classdev_register(dev->dev, &dev->led_cdev);
return led_classdev_register(dev->dev, &dev->led_cdev);
}
static void mt76_led_cleanup(struct mt76_dev *dev)
{
if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
return;
led_classdev_unregister(&dev->led_cdev);
}
static void mt76_init_stream_cap(struct mt76_dev *dev,
@ -180,6 +188,7 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
sband->bitrates = rates;
sband->n_bitrates = n_rates;
dev->chandef.chan = &sband->channels[0];
dev->chan_state = &msband->chan[0];
ht_cap = &sband->ht_cap;
ht_cap->ht_supported = true;
@ -306,6 +315,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
wiphy->available_antennas_tx = dev->antenna_mask;
wiphy->available_antennas_rx = dev->antenna_mask;
@ -327,8 +337,16 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
ieee80211_hw_set(hw, AP_LINK_PS);
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_ADHOC);
if (dev->cap.has_2ghz) {
ret = mt76_init_sband_2g(dev, rates, n_rates);
@ -360,6 +378,7 @@ void mt76_unregister_device(struct mt76_dev *dev)
{
struct ieee80211_hw *hw = dev->hw;
mt76_led_cleanup(dev);
mt76_tx_status_check(dev, NULL, true);
ieee80211_unregister_hw(hw);
}
@ -398,28 +417,64 @@ bool mt76_has_tx_pending(struct mt76_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
void mt76_set_channel(struct mt76_dev *dev)
static struct mt76_channel_state *
mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c)
{
struct ieee80211_hw *hw = dev->hw;
struct cfg80211_chan_def *chandef = &hw->conf.chandef;
struct mt76_channel_state *state;
bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
int timeout = HZ / 5;
struct mt76_sband *msband;
int idx;
wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
if (c->band == NL80211_BAND_2GHZ)
msband = &dev->sband_2g;
else
msband = &dev->sband_5g;
idx = c - &msband->sband.channels[0];
return &msband->chan[idx];
}
void mt76_update_survey(struct mt76_dev *dev)
{
struct mt76_channel_state *state = dev->chan_state;
ktime_t cur_time;
if (!test_bit(MT76_STATE_RUNNING, &dev->state))
return;
if (dev->drv->update_survey)
dev->drv->update_survey(dev);
cur_time = ktime_get_boottime();
state->cc_active += ktime_to_us(ktime_sub(cur_time,
dev->survey_time));
dev->survey_time = cur_time;
if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
spin_lock_bh(&dev->cc_lock);
state->cc_bss_rx += dev->cur_cc_bss_rx;
dev->cur_cc_bss_rx = 0;
spin_unlock_bh(&dev->cc_lock);
}
}
EXPORT_SYMBOL_GPL(mt76_update_survey);
void mt76_set_channel(struct mt76_dev *dev)
{
struct ieee80211_hw *hw = dev->hw;
struct cfg80211_chan_def *chandef = &hw->conf.chandef;
bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
int timeout = HZ / 5;
wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
mt76_update_survey(dev);
dev->chandef = *chandef;
dev->chan_state = mt76_channel_state(dev, chandef->chan);
if (!offchannel)
dev->main_chan = chandef->chan;
if (chandef->chan != dev->main_chan) {
state = mt76_channel_state(dev, chandef->chan);
memset(state, 0, sizeof(*state));
}
if (chandef->chan != dev->main_chan)
memset(dev->chan_state, 0, sizeof(*dev->chan_state));
}
EXPORT_SYMBOL_GPL(mt76_set_channel);
@ -432,8 +487,9 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
struct mt76_channel_state *state;
int ret = 0;
mutex_lock(&dev->mutex);
if (idx == 0 && dev->drv->update_survey)
dev->drv->update_survey(dev);
mt76_update_survey(dev);
sband = &dev->sband_2g;
if (idx >= sband->sband.n_channels) {
@ -441,8 +497,10 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
sband = &dev->sband_5g;
}
if (idx >= sband->sband.n_channels)
return -ENOENT;
if (idx >= sband->sband.n_channels) {
ret = -ENOENT;
goto out;
}
chan = &sband->sband.channels[idx];
state = mt76_channel_state(dev, chan);
@ -450,14 +508,26 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
memset(survey, 0, sizeof(*survey));
survey->channel = chan;
survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
if (chan == dev->main_chan)
survey->filled |= dev->drv->survey_flags;
if (chan == dev->main_chan) {
survey->filled |= SURVEY_INFO_IN_USE;
spin_lock_bh(&dev->cc_lock);
survey->time = div_u64(state->cc_active, 1000);
if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
survey->filled |= SURVEY_INFO_TIME_BSS_RX;
}
survey->time_busy = div_u64(state->cc_busy, 1000);
survey->time_rx = div_u64(state->cc_rx, 1000);
survey->time = div_u64(state->cc_active, 1000);
spin_lock_bh(&dev->cc_lock);
survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
survey->time_tx = div_u64(state->cc_tx, 1000);
spin_unlock_bh(&dev->cc_lock);
out:
mutex_unlock(&dev->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(mt76_get_survey);
@ -502,6 +572,7 @@ static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
status->band = mstat.band;
status->signal = mstat.signal;
status->chains = mstat.chains;
status->ampdu_reference = mstat.ampdu_ref;
BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
BUILD_BUG_ON(sizeof(status->chain_signal) !=
@ -551,6 +622,84 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
return 0;
}
static void
mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
int len)
{
struct mt76_wcid *wcid = status->wcid;
struct ieee80211_sta *sta;
u32 airtime;
airtime = mt76_calc_rx_airtime(dev, status, len);
spin_lock(&dev->cc_lock);
dev->cur_cc_bss_rx += airtime;
spin_unlock(&dev->cc_lock);
if (!wcid || !wcid->sta)
return;
sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
}
static void
mt76_airtime_flush_ampdu(struct mt76_dev *dev)
{
struct mt76_wcid *wcid;
int wcid_idx;
if (!dev->rx_ampdu_len)
return;
wcid_idx = dev->rx_ampdu_status.wcid_idx;
if (wcid_idx < ARRAY_SIZE(dev->wcid))
wcid = rcu_dereference(dev->wcid[wcid_idx]);
else
wcid = NULL;
dev->rx_ampdu_status.wcid = wcid;
mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
dev->rx_ampdu_len = 0;
dev->rx_ampdu_ref = 0;
}
static void
mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct mt76_wcid *wcid = status->wcid;
if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
return;
if (!wcid || !wcid->sta) {
if (!ether_addr_equal(hdr->addr1, dev->macaddr))
return;
wcid = NULL;
}
if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
status->ampdu_ref != dev->rx_ampdu_ref)
mt76_airtime_flush_ampdu(dev);
if (status->flag & RX_FLAG_AMPDU_DETAILS) {
if (!dev->rx_ampdu_len ||
status->ampdu_ref != dev->rx_ampdu_ref) {
dev->rx_ampdu_status = *status;
dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
dev->rx_ampdu_ref = status->ampdu_ref;
}
dev->rx_ampdu_len += skb->len;
return;
}
mt76_airtime_report(dev, status, skb->len);
}
static void
mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
{
@ -567,6 +716,8 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
}
mt76_airtime_check(dev, skb);
if (!wcid || !wcid->sta)
return;
@ -886,3 +1037,16 @@ void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
clear_bit(MT76_SCANNING, &dev->state);
}
EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
{
struct mt76_dev *dev = hw->priv;
mutex_lock(&dev->mutex);
*tx_ant = dev->antenna_mask;
*rx_ant = dev->antenna_mask;
mutex_unlock(&dev->mutex);
return 0;
}
EXPORT_SYMBOL_GPL(mt76_get_antenna);

View File

@ -49,8 +49,8 @@ struct mt76_bus_ops {
enum mt76_bus_type type;
};
#define mt76_is_usb(dev) ((dev)->mt76.bus->type == MT76_BUS_USB)
#define mt76_is_mmio(dev) ((dev)->mt76.bus->type == MT76_BUS_MMIO)
#define mt76_is_usb(dev) ((dev)->bus->type == MT76_BUS_USB)
#define mt76_is_mmio(dev) ((dev)->bus->type == MT76_BUS_MMIO)
enum mt76_txq_id {
MT_TXQ_VO = IEEE80211_AC_VO,
@ -152,10 +152,6 @@ struct mt76_queue_ops {
int idx, int n_desc, int bufsize,
u32 ring_base);
int (*add_buf)(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76_queue_buf *buf, int nbufs, u32 info,
struct sk_buff *skb, void *txwi);
int (*tx_queue_skb)(struct mt76_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta);
@ -191,8 +187,6 @@ DECLARE_EWMA(signal, 10, 8);
struct mt76_wcid {
struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS];
struct work_struct aggr_work;
unsigned long flags;
struct ewma_signal rssi;
@ -282,11 +276,13 @@ struct mt76_hw_cap {
bool has_5ghz;
};
#define MT_TXWI_NO_FREE BIT(0)
#define MT_DRV_TXWI_NO_FREE BIT(0)
#define MT_DRV_TX_ALIGNED4_SKBS BIT(1)
#define MT_DRV_SW_RX_AIRTIME BIT(2)
struct mt76_driver_ops {
bool tx_aligned4_skbs;
u32 txwi_flags;
u32 drv_flags;
u32 survey_flags;
u16 txwi_size;
void (*update_survey)(struct mt76_dev *dev);
@ -322,6 +318,9 @@ struct mt76_driver_ops {
struct mt76_channel_state {
u64 cc_active;
u64 cc_busy;
u64 cc_rx;
u64 cc_bss_rx;
u64 cc_tx;
};
struct mt76_sband {
@ -367,8 +366,8 @@ enum mt76u_in_ep {
enum mt76u_out_ep {
MT_EP_OUT_INBAND_CMD,
MT_EP_OUT_AC_BK,
MT_EP_OUT_AC_BE,
MT_EP_OUT_AC_BK,
MT_EP_OUT_AC_VI,
MT_EP_OUT_AC_VO,
MT_EP_OUT_HCCA,
@ -388,7 +387,8 @@ struct mt76_usb {
};
struct tasklet_struct rx_tasklet;
struct delayed_work stat_work;
struct workqueue_struct *stat_wq;
struct work_struct stat_work;
u8 out_ep[__MT_EP_OUT_MAX];
u8 in_ep[__MT_EP_IN_MAX];
@ -421,14 +421,49 @@ struct mt76_mmio {
u32 irqmask;
};
struct mt76_rx_status {
union {
struct mt76_wcid *wcid;
u8 wcid_idx;
};
unsigned long reorder_time;
u32 ampdu_ref;
u8 iv[6];
u8 aggr:1;
u8 tid;
u16 seqno;
u16 freq;
u32 flag;
u8 enc_flags;
u8 encoding:2, bw:3;
u8 rate_idx;
u8 nss;
u8 band;
s8 signal;
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
};
struct mt76_dev {
struct ieee80211_hw *hw;
struct cfg80211_chan_def chandef;
struct ieee80211_channel *main_chan;
struct mt76_channel_state *chan_state;
spinlock_t lock;
spinlock_t cc_lock;
u32 cur_cc_bss_rx;
struct mt76_rx_status rx_ampdu_status;
u32 rx_ampdu_len;
u32 rx_ampdu_ref;
struct mutex mutex;
const struct mt76_bus_ops *bus;
@ -440,6 +475,7 @@ struct mt76_dev {
spinlock_t rx_lock;
struct napi_struct napi[__MT_RXQ_MAX];
struct sk_buff_head rx_skb[__MT_RXQ_MAX];
u32 ampdu_ref;
struct list_head txwi_cache;
struct mt76_sw_queue q_tx[__MT_TXQ_MAX];
@ -463,6 +499,8 @@ struct mt76_dev {
u32 rev;
unsigned long state;
u32 aggr_stats[32];
u8 antenna_mask;
u16 chainmask;
@ -509,29 +547,6 @@ enum mt76_phy_type {
MT_PHY_TYPE_VHT,
};
struct mt76_rx_status {
struct mt76_wcid *wcid;
unsigned long reorder_time;
u8 iv[6];
u8 aggr:1;
u8 tid;
u16 seqno;
u16 freq;
u32 flag;
u8 enc_flags;
u8 encoding:2, bw:3;
u8 rate_idx;
u8 nss;
u8 band;
s8 signal;
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
};
#define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__)
#define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__)
#define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__)
@ -602,21 +617,6 @@ static inline u16 mt76_rev(struct mt76_dev *dev)
#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__)
static inline struct mt76_channel_state *
mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c)
{
struct mt76_sband *msband;
int idx;
if (c->band == NL80211_BAND_2GHZ)
msband = &dev->sband_2g;
else
msband = &dev->sband_5g;
idx = c - &msband->sband.channels[0];
return &msband->chan[idx];
}
struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size,
const struct ieee80211_ops *ops,
const struct mt76_driver_ops *drv_ops);
@ -626,6 +626,7 @@ void mt76_unregister_device(struct mt76_dev *dev);
void mt76_free_device(struct mt76_dev *dev);
struct dentry *mt76_register_debugfs(struct mt76_dev *dev);
int mt76_queues_read(struct seq_file *s, void *data);
void mt76_seq_puts_array(struct seq_file *file, const char *str,
s8 *val, int len);
@ -718,6 +719,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw,
bool more_data);
bool mt76_has_tx_pending(struct mt76_dev *dev);
void mt76_set_channel(struct mt76_dev *dev);
void mt76_update_survey(struct mt76_dev *dev);
int mt76_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey);
void mt76_set_stream_caps(struct mt76_dev *dev, bool vht);
@ -759,6 +761,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
void mt76_csa_check(struct mt76_dev *dev);
void mt76_csa_finish(struct mt76_dev *dev);
int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id);
int mt76_get_rate(struct mt76_dev *dev,
@ -768,6 +771,8 @@ void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const u8 *mac);
void mt76_sw_scan_complete(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info,
int len);
/* internal */
void mt76_tx_free(struct mt76_dev *dev);
@ -778,6 +783,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
struct napi_struct *napi);
void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames);
u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status,
int len);
/* usb */
static inline bool mt76u_urb_error(struct urb *urb)
@ -799,7 +806,8 @@ static inline int
mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
int timeout)
{
struct usb_device *udev = to_usb_device(dev->dev);
struct usb_interface *uintf = to_usb_interface(dev->dev);
struct usb_device *udev = interface_to_usbdev(uintf);
struct mt76_usb *usb = &dev->usb;
unsigned int pipe;
@ -817,6 +825,7 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req,
void mt76u_single_wr(struct mt76_dev *dev, const u8 req,
const u16 offset, const u32 val);
int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf);
void mt76u_deinit(struct mt76_dev *dev);
int mt76u_alloc_queues(struct mt76_dev *dev);
void mt76u_stop_tx(struct mt76_dev *dev);
void mt76u_stop_rx(struct mt76_dev *dev);

View File

@ -69,6 +69,41 @@ mt7603_edcca_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get,
mt7603_edcca_set, "%lld\n");
static int
mt7603_ampdu_stat_read(struct seq_file *file, void *data)
{
struct mt7603_dev *dev = file->private;
int bound[3], i, range;
range = mt76_rr(dev, MT_AGG_ASRCR);
for (i = 0; i < ARRAY_SIZE(bound); i++)
bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1;
seq_printf(file, "Length: %8d | ", bound[0]);
for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
seq_printf(file, "%3d -%3d | ",
bound[i], bound[i + 1]);
seq_puts(file, "\nCount: ");
for (i = 0; i < ARRAY_SIZE(bound); i++)
seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
seq_puts(file, "\n");
return 0;
}
static int
mt7603_ampdu_stat_open(struct inode *inode, struct file *f)
{
return single_open(f, mt7603_ampdu_stat_read, inode->i_private);
}
static const struct file_operations fops_ampdu_stat = {
.open = mt7603_ampdu_stat_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
void mt7603_init_debugfs(struct mt7603_dev *dev)
{
struct dentry *dir;
@ -77,6 +112,9 @@ void mt7603_init_debugfs(struct mt7603_dev *dev)
if (!dir)
return;
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
mt76_queues_read);
debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test);
debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir,

View File

@ -152,6 +152,8 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget)
for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false);
mt7603_mac_sta_poll(dev);
tasklet_schedule(&dev->mt76.tx_tasklet);
return 0;

View File

@ -7,6 +7,8 @@
const struct mt76_driver_ops mt7603_drv_ops = {
.txwi_size = MT_TXD_SIZE,
.drv_flags = MT_DRV_SW_RX_AIRTIME,
.survey_flags = SURVEY_INFO_TIME_TX,
.tx_prepare_skb = mt7603_tx_prepare_skb,
.tx_complete_skb = mt7603_tx_complete_skb,
.rx_skb = mt7603_queue_rx_skb,
@ -524,6 +526,8 @@ int mt7603_register_device(struct mt7603_dev *dev)
bus_ops->rmw = mt7603_rmw;
dev->mt76.bus = bus_ops;
INIT_LIST_HEAD(&dev->sta_poll_list);
spin_lock_init(&dev->sta_poll_lock);
spin_lock_init(&dev->ps_lock);
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work);
@ -552,7 +556,6 @@ int mt7603_register_device(struct mt7603_dev *dev)
wiphy->iface_combinations = if_comb;
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
/* init led callbacks */
@ -561,16 +564,7 @@ int mt7603_register_device(struct mt7603_dev *dev)
dev->mt76.led_cdev.blink_set = mt7603_led_set_blink;
}
wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_ADHOC);
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
wiphy->reg_notifier = mt7603_regd_notifier;
ret = mt76_register_device(&dev->mt76, true, mt7603_rates,

View File

@ -31,6 +31,16 @@ mt76_start_tx_ac(struct mt7603_dev *dev, u32 mask)
mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask));
}
void mt7603_mac_reset_counters(struct mt7603_dev *dev)
{
int i;
for (i = 0; i < 2; i++)
mt76_rr(dev, MT_TX_AGG_CNT(i));
memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
}
void mt7603_mac_set_timing(struct mt7603_dev *dev)
{
u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
@ -150,6 +160,8 @@ void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif,
addr = mt7603_wtbl4_addr(idx);
for (i = 0; i < MT_WTBL4_SIZE; i += 4)
mt76_wr(dev, addr + i, 0);
mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
}
static void
@ -370,6 +382,84 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid,
mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val);
}
void mt7603_mac_sta_poll(struct mt7603_dev *dev)
{
static const u8 ac_to_tid[4] = {
[IEEE80211_AC_BE] = 0,
[IEEE80211_AC_BK] = 1,
[IEEE80211_AC_VI] = 4,
[IEEE80211_AC_VO] = 6
};
struct ieee80211_sta *sta;
struct mt7603_sta *msta;
u32 total_airtime = 0;
u32 airtime[4];
u32 addr;
int i;
rcu_read_lock();
while (1) {
bool clear = false;
spin_lock_bh(&dev->sta_poll_lock);
if (list_empty(&dev->sta_poll_list)) {
spin_unlock_bh(&dev->sta_poll_lock);
break;
}
msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta,
poll_list);
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
addr = mt7603_wtbl4_addr(msta->wcid.idx);
for (i = 0; i < 4; i++) {
u32 airtime_last = msta->tx_airtime_ac[i];
msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8);
airtime[i] = msta->tx_airtime_ac[i] - airtime_last;
airtime[i] *= 32;
total_airtime += airtime[i];
if (msta->tx_airtime_ac[i] & BIT(22))
clear = true;
}
if (clear) {
mt7603_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
memset(msta->tx_airtime_ac, 0,
sizeof(msta->tx_airtime_ac));
}
if (!msta->wcid.sta)
continue;
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
for (i = 0; i < 4; i++) {
struct mt76_queue *q = dev->mt76.q_tx[i].q;
u8 qidx = q->hw_idx;
u8 tid = ac_to_tid[i];
u32 txtime = airtime[qidx];
if (!txtime)
continue;
ieee80211_sta_register_airtime(sta, tid, txtime, 0);
}
}
rcu_read_unlock();
if (!total_airtime)
return;
spin_lock_bh(&dev->mt76.cc_lock);
dev->mt76.chan_state->cc_tx += total_airtime;
spin_unlock_bh(&dev->mt76.cc_lock);
}
static struct mt76_wcid *
mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast)
{
@ -435,6 +525,20 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
}
if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
MT_RXD2_NORMAL_NON_AMPDU))) {
status->flag |= RX_FLAG_AMPDU_DETAILS;
/* all subframes of an A-MPDU have the same timestamp */
if (dev->rx_ampdu_ts != rxd[12]) {
if (!++dev->mt76.ampdu_ref)
dev->mt76.ampdu_ref++;
}
dev->rx_ampdu_ts = rxd[12];
status->ampdu_ref = dev->mt76.ampdu_ref;
}
remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
@ -1032,8 +1136,10 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
if (idx && (cur_rate->idx != info->status.rates[i].idx ||
cur_rate->flags != info->status.rates[i].flags)) {
i++;
if (i == ARRAY_SIZE(info->status.rates))
if (i == ARRAY_SIZE(info->status.rates)) {
i--;
break;
}
info->status.rates[i] = *cur_rate;
info->status.rates[i].count = 0;
@ -1135,6 +1241,12 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
msta = container_of(wcid, struct mt7603_sta, wcid);
sta = wcid_to_sta(wcid);
if (list_empty(&msta->poll_list)) {
spin_lock_bh(&dev->sta_poll_lock);
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
}
if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data))
goto out;
@ -1461,22 +1573,9 @@ void mt7603_update_channel(struct mt76_dev *mdev)
{
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
struct mt76_channel_state *state;
ktime_t cur_time;
u32 busy;
if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
return;
state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan);
busy = mt76_rr(dev, MT_MIB_STAT_PSCCA);
spin_lock_bh(&dev->mt76.cc_lock);
cur_time = ktime_get_boottime();
state->cc_busy += busy;
state->cc_active += ktime_to_us(ktime_sub(cur_time,
dev->mt76.survey_time));
dev->mt76.survey_time = cur_time;
spin_unlock_bh(&dev->mt76.cc_lock);
state = mdev->chan_state;
state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA);
}
void
@ -1677,15 +1776,23 @@ void mt7603_mac_work(struct work_struct *work)
struct mt7603_dev *dev = container_of(work, struct mt7603_dev,
mt76.mac_work.work);
bool reset = false;
int i, idx;
mt76_tx_status_check(&dev->mt76, NULL, false);
mutex_lock(&dev->mt76.mutex);
dev->mac_work_count++;
mt7603_update_channel(&dev->mt76);
mt76_update_survey(&dev->mt76);
mt7603_edcca_check(dev);
for (i = 0, idx = 0; i < 2; i++) {
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
dev->mt76.aggr_stats[idx++] += val & 0xffff;
dev->mt76.aggr_stats[idx++] += val >> 16;
}
if (dev->mac_work_count == 10)
mt7603_false_cca_check(dev);

View File

@ -13,6 +13,7 @@ mt7603_start(struct ieee80211_hw *hw)
{
struct mt7603_dev *dev = hw->priv;
mt7603_mac_reset_counters(dev);
mt7603_mac_start(dev);
dev->mt76.survey_time = ktime_get_boottime();
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
@ -65,6 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
idx = MT7603_WTBL_RESERVED - 1 - mvif->idx;
dev->vif_mask |= BIT(mvif->idx);
INIT_LIST_HEAD(&mvif->sta.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.hw_key_idx = -1;
@ -86,8 +88,9 @@ static void
mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
struct mt7603_sta *msta = &mvif->sta;
struct mt7603_dev *dev = hw->priv;
int idx = mvif->sta.wcid.idx;
int idx = msta->wcid.idx;
mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), 0);
mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), 0);
@ -98,6 +101,11 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
mt76_txq_remove(&dev->mt76, vif->txq);
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
mutex_lock(&dev->mt76.mutex);
dev->vif_mask &= ~BIT(mvif->idx);
mutex_unlock(&dev->mt76.mutex);
@ -324,6 +332,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (idx < 0)
return -ENOSPC;
INIT_LIST_HEAD(&msta->poll_list);
__skb_queue_head_init(&msta->psq);
msta->ps = ~0;
msta->smps = ~0;
@ -360,6 +369,11 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt7603_filter_tx(dev, wcid->idx, true);
spin_unlock_bh(&dev->ps_lock);
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
mt7603_wtbl_clear(dev, wcid->idx);
}
@ -555,12 +569,14 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 ssn = params->ssn;
u8 ba_size = params->buf_size;
struct mt76_txq *mtxq;
int ret = 0;
if (!txq)
return -EINVAL;
mtxq = (struct mt76_txq *)txq->drv_priv;
mutex_lock(&dev->mt76.mutex);
switch (action) {
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
@ -582,15 +598,17 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
break;
case IEEE80211_AMPDU_TX_START:
mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
return IEEE80211_AMPDU_TX_START_IMMEDIATE;
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, -1);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
mutex_unlock(&dev->mt76.mutex);
return 0;
return ret;
}
static void
@ -675,6 +693,7 @@ const struct ieee80211_ops mt7603_ops = {
.set_coverage_class = mt7603_set_coverage_class,
.set_tim = mt76_set_tim,
.get_survey = mt76_get_survey,
.get_antenna = mt76_get_antenna,
};
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -61,6 +61,9 @@ struct mt7603_sta {
struct mt7603_vif *vif;
struct list_head poll_list;
u32 tx_airtime_ac[4];
struct sk_buff_head psq;
struct ieee80211_tx_rate rates[4];
@ -103,12 +106,16 @@ struct mt7603_dev {
u8 vif_mask;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
struct mt7603_sta global_sta;
u32 agc0, agc3;
u32 false_cca_ofdm, false_cca_cck;
unsigned long last_cca_adj;
__le32 rx_ampdu_ts;
u8 rssi_offset[3];
u8 slottime;
@ -118,8 +125,6 @@ struct mt7603_dev {
ktime_t ed_time;
struct mt76_queue q_rx;
spinlock_t ps_lock;
u8 mac_work_count;
@ -191,6 +196,7 @@ static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask)
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
}
void mt7603_mac_reset_counters(struct mt7603_dev *dev);
void mt7603_mac_dma_start(struct mt7603_dev *dev);
void mt7603_mac_start(struct mt7603_dev *dev);
void mt7603_mac_stop(struct mt7603_dev *dev);
@ -202,6 +208,7 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data);
void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid);
void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid,
int ba_size);
void mt7603_mac_sta_poll(struct mt7603_dev *dev);
void mt7603_pse_client_reset(struct mt7603_dev *dev);

View File

@ -212,6 +212,9 @@
#define MT_AGG_PCR_RTS_THR GENMASK(19, 0)
#define MT_AGG_PCR_RTS_PKT_THR GENMASK(31, 25)
#define MT_AGG_ASRCR MT_WF_AGG(0x060)
#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0))
#define MT_AGG_CONTROL MT_WF_AGG(0x070)
#define MT_AGG_CONTROL_NO_BA_RULE BIT(0)
#define MT_AGG_CONTROL_NO_BA_AR_RULE BIT(1)
@ -555,6 +558,8 @@ enum {
#define MT_MIB_STAT_PSCCA MT_MIB_STAT(16)
#define MT_MIB_STAT_PSCCA_MASK GENMASK(23, 0)
#define MT_TX_AGG_CNT(n) MT_MIB(0xa8 + ((n) << 2))
#define MT_MIB_STAT_ED MT_MIB_STAT(18)
#define MT_MIB_STAT_ED_MASK GENMASK(23, 0)

View File

@ -36,6 +36,44 @@ mt7615_scs_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_scs, mt7615_scs_get,
mt7615_scs_set, "%lld\n");
static int
mt7615_ampdu_stat_read(struct seq_file *file, void *data)
{
struct mt7615_dev *dev = file->private;
int bound[7], i, range;
range = mt76_rr(dev, MT_AGG_ASRCR0);
for (i = 0; i < 4; i++)
bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1;
range = mt76_rr(dev, MT_AGG_ASRCR1);
for (i = 0; i < 3; i++)
bound[i + 4] = MT_AGG_ASRCR_RANGE(range, i) + 1;
seq_printf(file, "Length: %8d | ", bound[0]);
for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
seq_printf(file, "%3d -%3d | ",
bound[i], bound[i + 1]);
seq_puts(file, "\nCount: ");
for (i = 0; i < ARRAY_SIZE(bound); i++)
seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
seq_puts(file, "\n");
return 0;
}
static int
mt7615_ampdu_stat_open(struct inode *inode, struct file *f)
{
return single_open(f, mt7615_ampdu_stat_read, inode->i_private);
}
static const struct file_operations fops_ampdu_stat = {
.open = mt7615_ampdu_stat_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int
mt7615_radio_read(struct seq_file *s, void *data)
{
@ -61,6 +99,63 @@ static int mt7615_read_temperature(struct seq_file *s, void *data)
return 0;
}
static int
mt7615_queues_acq(struct seq_file *s, void *data)
{
struct mt7615_dev *dev = dev_get_drvdata(s->private);
int i;
for (i = 0; i < 16; i++) {
int j, acs = i / 4, index = i % 4;
u32 ctrl, val, qlen = 0;
val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
ctrl = BIT(31) | BIT(15) | (acs << 8);
for (j = 0; j < 32; j++) {
if (val & BIT(j))
continue;
mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
ctrl | (j + (index << 5)));
qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
GENMASK(11, 0));
}
seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
}
return 0;
}
static int
mt7615_queues_read(struct seq_file *s, void *data)
{
struct mt7615_dev *dev = dev_get_drvdata(s->private);
static const struct {
char *queue;
int id;
} queue_map[] = {
{ "PDMA0", MT_TXQ_BE },
{ "MCUQ", MT_TXQ_MCU },
{ "MCUFWQ", MT_TXQ_FWDL },
};
int i;
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id];
if (!q->q)
continue;
seq_printf(s,
"%s: queued=%d head=%d tail=%d\n",
queue_map[i].queue, q->q->queued, q->q->head,
q->q->tail);
}
return 0;
}
int mt7615_init_debugfs(struct mt7615_dev *dev)
{
struct dentry *dir;
@ -69,6 +164,11 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
if (!dir)
return -ENOMEM;
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
mt7615_queues_read);
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
mt7615_queues_acq);
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
debugfs_create_file("scs", 0600, dir, dev, &fops_scs);
debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir,
mt7615_radio_read);

View File

@ -110,6 +110,8 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
for (i = 0; i < ARRAY_SIZE(queue_map); i++)
mt76_queue_tx_cleanup(dev, queue_map[i], false);
mt7615_mac_sta_poll(dev);
tasklet_schedule(&dev->mt76.tx_tasklet);
return 0;

View File

@ -93,6 +93,7 @@ static int mt7615_check_eeprom(struct mt76_dev *dev)
static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
{
u8 val, *eeprom = dev->mt76.eeprom.data;
u8 tx_mask, rx_mask, max_nss;
val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL,
eeprom[MT_EE_WIFI_CONF]);
@ -108,6 +109,23 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
dev->mt76.cap.has_5ghz = true;
break;
}
/* read tx-rx mask from eeprom */
val = mt76_rr(dev, MT_TOP_STRAP_STA);
max_nss = val & MT_TOP_3NSS ? 3 : 4;
rx_mask = FIELD_GET(MT_EE_NIC_CONF_RX_MASK,
eeprom[MT_EE_NIC_CONF_0]);
if (!rx_mask || rx_mask > max_nss)
rx_mask = max_nss;
tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK,
eeprom[MT_EE_NIC_CONF_0]);
if (!tx_mask || tx_mask > max_nss)
tx_mask = max_nss;
dev->mt76.chainmask = tx_mask << 8 | rx_mask;
dev->mt76.antenna_mask = BIT(tx_mask) - 1;
}
int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,

View File

@ -24,6 +24,9 @@ enum mt7615_eeprom_field {
__MT_EE_MAX = 0x3bf
};
#define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4)
#define MT_EE_NIC_CONF_RX_MASK GENMASK(3, 0)
#define MT_EE_NIC_CONF_TSSI_2G BIT(5)
#define MT_EE_NIC_CONF_TSSI_5G BIT(6)

View File

@ -20,7 +20,8 @@ static void mt7615_phy_init(struct mt7615_dev *dev)
static void mt7615_mac_init(struct mt7615_dev *dev)
{
u32 val;
u32 val, mask, set;
int i;
/* enable band 0/1 clk */
mt76_set(dev, MT_CFG_CCR,
@ -50,7 +51,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
MT_TMAC_CTCR0_INS_DDLMT_EN);
mt7615_mcu_set_rts_thresh(dev, 0x92b);
mt7615_mac_set_scs(dev, false);
mt7615_mac_set_scs(dev, true);
mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS,
MT_AGG_SCR_NLNAV_MID_PTEC_DIS);
@ -85,6 +86,24 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
MT_AGG_ARCR_RATE_DOWN_RATIO_EN |
FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) |
FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4)));
mask = MT_DMA_RCFR0_MCU_RX_MGMT |
MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR |
MT_DMA_RCFR0_MCU_RX_CTL_BAR |
MT_DMA_RCFR0_MCU_RX_BYPASS |
MT_DMA_RCFR0_RX_DROPPED_UCAST |
MT_DMA_RCFR0_RX_DROPPED_MCAST;
set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) |
FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2);
mt76_rmw(dev, MT_DMA_BN0RCFR0, mask, set);
mt76_rmw(dev, MT_DMA_BN1RCFR0, mask, set);
for (i = 0; i < MT7615_WTBL_SIZE; i++)
mt7615_mac_wtbl_update(dev, i,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_EN);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_EN);
}
static int mt7615_init_hardware(struct mt7615_dev *dev)
@ -158,6 +177,9 @@ static struct ieee80211_rate mt7615_rates[] = {
static const struct ieee80211_iface_limit if_limits[] = {
{
.max = 1,
.types = BIT(NL80211_IFTYPE_ADHOC)
}, {
.max = MT7615_MAX_INTERFACES,
.types = BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH
@ -249,12 +271,14 @@ int mt7615_register_device(struct mt7615_dev *dev)
struct wiphy *wiphy = hw->wiphy;
int ret;
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
INIT_LIST_HEAD(&dev->sta_poll_list);
spin_lock_init(&dev->sta_poll_lock);
ret = mt7615_init_hardware(dev);
if (ret)
return ret;
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
hw->queues = 4;
hw->max_rates = 3;
hw->max_report_rates = 7;
@ -268,7 +292,8 @@ int mt7615_register_device(struct mt7615_dev *dev)
wiphy->reg_notifier = mt7615_regd_notifier;
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
@ -278,16 +303,8 @@ int mt7615_register_device(struct mt7615_dev *dev)
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
dev->mt76.chainmask = 0x404;
dev->mt76.antenna_mask = 0xf;
dev->dfs_state = -1;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_AP);
ret = mt76_register_device(&dev->mt76, true, mt7615_rates,
ARRAY_SIZE(mt7615_rates));
if (ret)

View File

@ -41,6 +41,25 @@ static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
return &sta->vif->sta.wcid;
}
void mt7615_mac_reset_counters(struct mt7615_dev *dev)
{
int i;
for (i = 0; i < 4; i++)
mt76_rr(dev, MT_TX_AGG_CNT(i));
memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
/* TODO: add DBDC support */
/* reset airtime counters */
mt76_rr(dev, MT_MIB_SDR9(0));
mt76_rr(dev, MT_MIB_SDR36(0));
mt76_rr(dev, MT_MIB_SDR37(0));
mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
}
int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
@ -62,6 +81,16 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
status->wcid = mt7615_rx_get_wcid(dev, idx, unicast);
if (status->wcid) {
struct mt7615_sta *msta;
msta = container_of(status->wcid, struct mt7615_sta, wcid);
spin_lock_bh(&dev->sta_poll_lock);
if (list_empty(&msta->poll_list))
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
}
/* TODO: properly support DBDC */
status->freq = dev->mt76.chandef.chan->center_freq;
status->band = dev->mt76.chandef.chan->band;
@ -83,6 +112,20 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
}
if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
MT_RXD2_NORMAL_NON_AMPDU))) {
status->flag |= RX_FLAG_AMPDU_DETAILS;
/* all subframes of an A-MPDU have the same timestamp */
if (dev->rx_ampdu_ts != rxd[12]) {
if (!++dev->mt76.ampdu_ref)
dev->mt76.ampdu_ref++;
}
dev->rx_ampdu_ts = rxd[12];
status->ampdu_ref = dev->mt76.ampdu_ref;
}
remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
@ -460,6 +503,91 @@ static u32 mt7615_mac_wtbl_addr(int wcid)
return MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE;
}
bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask)
{
mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
0, 5000);
}
void mt7615_mac_sta_poll(struct mt7615_dev *dev)
{
static const u8 ac_to_tid[4] = {
[IEEE80211_AC_BE] = 0,
[IEEE80211_AC_BK] = 1,
[IEEE80211_AC_VI] = 4,
[IEEE80211_AC_VO] = 6
};
static const u8 hw_queue_map[] = {
[IEEE80211_AC_BK] = 0,
[IEEE80211_AC_BE] = 1,
[IEEE80211_AC_VI] = 2,
[IEEE80211_AC_VO] = 3,
};
struct ieee80211_sta *sta;
struct mt7615_sta *msta;
u32 addr, tx_time[4], rx_time[4];
int i;
rcu_read_lock();
while (true) {
bool clear = false;
spin_lock_bh(&dev->sta_poll_lock);
if (list_empty(&dev->sta_poll_list)) {
spin_unlock_bh(&dev->sta_poll_lock);
break;
}
msta = list_first_entry(&dev->sta_poll_list,
struct mt7615_sta, poll_list);
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
addr = mt7615_mac_wtbl_addr(msta->wcid.idx) + 19 * 4;
for (i = 0; i < 4; i++, addr += 8) {
u32 tx_last = msta->airtime_ac[i];
u32 rx_last = msta->airtime_ac[i + 4];
msta->airtime_ac[i] = mt76_rr(dev, addr);
msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
tx_time[i] = msta->airtime_ac[i] - tx_last;
rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
if ((tx_last | rx_last) & BIT(30))
clear = true;
}
if (clear) {
mt7615_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
}
if (!msta->wcid.sta)
continue;
sta = container_of((void *)msta, struct ieee80211_sta,
drv_priv);
for (i = 0; i < 4; i++) {
u32 tx_cur = tx_time[i];
u32 rx_cur = rx_time[hw_queue_map[i]];
u8 tid = ac_to_tid[i];
if (!tx_cur && !rx_cur)
continue;
ieee80211_sta_register_airtime(sta, tid, tx_cur,
rx_cur);
}
}
rcu_read_unlock();
}
void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
struct ieee80211_tx_rate *probe_rate,
struct ieee80211_tx_rate *rates)
@ -692,11 +820,8 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
mt76_wr(dev, MT_WTBL_RICR0, w0);
mt76_wr(dev, MT_WTBL_RICR1, w1);
mt76_wr(dev, MT_WTBL_UPDATE,
FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid->idx) |
MT_WTBL_UPDATE_RXINFO_UPDATE);
if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
if (!mt7615_mac_wtbl_update(dev, wcid->idx,
MT_WTBL_UPDATE_RXINFO_UPDATE))
return -ETIMEDOUT;
return 0;
@ -914,8 +1039,10 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
if (idx && (cur_rate->idx != info->status.rates[i].idx ||
cur_rate->flags != info->status.rates[i].flags)) {
i++;
if (i == ARRAY_SIZE(info->status.rates))
if (i == ARRAY_SIZE(info->status.rates)) {
i--;
break;
}
info->status.rates[i] = *cur_rate;
info->status.rates[i].count = 0;
@ -1026,6 +1153,11 @@ void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
msta = container_of(wcid, struct mt7615_sta, wcid);
sta = wcid_to_sta(wcid);
spin_lock_bh(&dev->sta_poll_lock);
if (list_empty(&msta->poll_list))
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
goto out;
@ -1239,38 +1371,49 @@ void mt7615_update_channel(struct mt76_dev *mdev)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
struct mt76_channel_state *state;
ktime_t cur_time;
u32 busy;
u64 busy_time, tx_time, rx_time, obss_time;
if (!test_bit(MT76_STATE_RUNNING, &mdev->state))
return;
state = mt76_channel_state(mdev, mdev->chandef.chan);
/* TODO: add DBDC support */
busy = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK);
busy_time = mt76_get_field(dev, MT_MIB_SDR9(0),
MT_MIB_SDR9_BUSY_MASK);
tx_time = mt76_get_field(dev, MT_MIB_SDR36(0),
MT_MIB_SDR36_TXTIME_MASK);
rx_time = mt76_get_field(dev, MT_MIB_SDR37(0),
MT_MIB_SDR37_RXTIME_MASK);
obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_TIME5,
MT_MIB_OBSSTIME_MASK);
spin_lock_bh(&mdev->cc_lock);
cur_time = ktime_get_boottime();
state->cc_busy += busy;
state->cc_active += ktime_to_us(ktime_sub(cur_time,
mdev->survey_time));
mdev->survey_time = cur_time;
spin_unlock_bh(&mdev->cc_lock);
state = mdev->chan_state;
state->cc_busy += busy_time;
state->cc_tx += tx_time;
state->cc_rx += rx_time + obss_time;
state->cc_bss_rx += rx_time;
/* reset obss airtime */
mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
}
void mt7615_mac_work(struct work_struct *work)
{
struct mt7615_dev *dev;
int i, idx;
dev = (struct mt7615_dev *)container_of(work, struct mt76_dev,
mac_work.work);
mutex_lock(&dev->mt76.mutex);
mt7615_update_channel(&dev->mt76);
mt76_update_survey(&dev->mt76);
if (++dev->mac_work_count == 5) {
mt7615_mac_scs_check(dev);
dev->mac_work_count = 0;
}
for (i = 0, idx = 0; i < 4; i++) {
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
dev->mt76.aggr_stats[idx++] += val & 0xffff;
dev->mt76.aggr_stats[idx++] += val >> 16;
}
mutex_unlock(&dev->mt76.mutex);
mt76_tx_status_check(&dev->mt76, NULL, false);

View File

@ -16,6 +16,8 @@ static int mt7615_start(struct ieee80211_hw *hw)
{
struct mt7615_dev *dev = hw->priv;
mt7615_mac_reset_counters(dev);
dev->mt76.survey_time = ktime_get_boottime();
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
@ -39,6 +41,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask)
switch (type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
/* ap use hw bssid 0 and ext bssid */
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
@ -58,7 +61,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask)
default:
WARN_ON(1);
break;
};
}
return -1;
}
@ -97,8 +100,12 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
dev->vif_mask |= BIT(mvif->idx);
dev->omac_mask |= BIT(mvif->omac_idx);
idx = MT7615_WTBL_RESERVED - mvif->idx;
INIT_LIST_HEAD(&mvif->sta.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.hw_key_idx = -1;
mt7615_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
@ -115,8 +122,9 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
struct mt7615_sta *msta = &mvif->sta;
struct mt7615_dev *dev = hw->priv;
int idx = mvif->sta.wcid.idx;
int idx = msta->wcid.idx;
/* TODO: disable beacon for the bss */
@ -129,6 +137,11 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
dev->vif_mask &= ~BIT(mvif->idx);
dev->omac_mask &= ~BIT(mvif->omac_idx);
mutex_unlock(&dev->mt76.mutex);
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
}
static int mt7615_set_channel(struct mt7615_dev *dev)
@ -151,8 +164,8 @@ static int mt7615_set_channel(struct mt7615_dev *dev)
ret = mt7615_dfs_init_radar_detector(dev);
mt7615_mac_cca_stats_reset(dev);
dev->mt76.survey_time = ktime_get_boottime();
/* TODO: add DBDC support */
mt76_rr(dev, MT_MIB_SDR16(0));
mt7615_mac_reset_counters(dev);
out:
clear_bit(MT76_RESET, &dev->mt76.state);
@ -263,6 +276,11 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
u64 multicast)
{
struct mt7615_dev *dev = hw->priv;
u32 ctl_flags = MT_WF_RFCR1_DROP_ACK |
MT_WF_RFCR1_DROP_BF_POLL |
MT_WF_RFCR1_DROP_BA |
MT_WF_RFCR1_DROP_CFEND |
MT_WF_RFCR1_DROP_CFACK;
u32 flags = 0;
#define MT76_FILTER(_flag, _hw) do { \
@ -296,6 +314,11 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
*total_flags = flags;
mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter);
if (*total_flags & FIF_CONTROL)
mt76_clear(dev, MT_WF_RFCR1, ctl_flags);
else
mt76_set(dev, MT_WF_RFCR1, ctl_flags);
}
static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
@ -348,9 +371,12 @@ int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (idx < 0)
return -ENOSPC;
INIT_LIST_HEAD(&msta->poll_list);
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
mt7615_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
mt7615_mcu_add_wtbl(dev, vif, sta);
mt7615_mcu_set_sta_rec(dev, vif, sta, 1);
@ -371,9 +397,18 @@ void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
mt7615_mcu_set_sta_rec(dev, vif, sta, 0);
mt7615_mcu_del_wtbl(dev, sta);
mt7615_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
}
static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
@ -449,12 +484,14 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 tid = params->tid;
u16 ssn = params->ssn;
struct mt76_txq *mtxq;
int ret = 0;
if (!txq)
return -EINVAL;
mtxq = (struct mt76_txq *)txq->drv_priv;
mutex_lock(&dev->mt76.mutex);
switch (action) {
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
@ -477,15 +514,17 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
break;
case IEEE80211_AMPDU_TX_START:
mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
return IEEE80211_AMPDU_TX_START_IMMEDIATE;
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
mt7615_mcu_set_tx_ba(dev, params, 0);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
mutex_unlock(&dev->mt76.mutex);
return 0;
return ret;
}
const struct ieee80211_ops mt7615_ops = {
@ -510,4 +549,5 @@ const struct ieee80211_ops mt7615_ops = {
.get_txpower = mt76_get_txpower,
.channel_switch_beacon = mt7615_channel_switch_beacon,
.get_survey = mt76_get_survey,
.get_antenna = mt76_get_antenna,
};

View File

@ -848,6 +848,11 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
conn_type = CONNECTION_INFRA_STA;
break;
}
case NL80211_IFTYPE_ADHOC:
conn_type = CONNECTION_IBSS_ADHOC;
tx_wlan_idx = mvif->sta.wcid.idx;
net_type = NETWORK_IBSS;
break;
default:
WARN_ON(1);
break;
@ -1073,10 +1078,13 @@ int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif,
case NL80211_IFTYPE_STATION:
req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP);
break;
case NL80211_IFTYPE_ADHOC:
req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);
break;
default:
WARN_ON(1);
break;
};
}
if (en) {
req.basic.conn_state = CONN_STATE_PORT_SECURE;
@ -1297,8 +1305,10 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev)
};
int ret;
if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
req.switch_reason = CH_SWITCH_DFS;
else
req.switch_reason = CH_SWITCH_NORMAL;

View File

@ -56,6 +56,9 @@ struct mt7615_sta {
struct mt7615_vif *vif;
struct list_head poll_list;
u32 airtime_ac[8];
struct ieee80211_tx_rate rates[4];
struct mt7615_rate_set rateset[2];
@ -81,6 +84,11 @@ struct mt7615_dev {
u32 vif_mask;
u32 omac_mask;
__le32 rx_ampdu_ts;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
struct {
u8 n_pulses;
u32 period;
@ -229,8 +237,11 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask)
}
void mt7615_update_channel(struct mt76_dev *mdev);
bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask);
void mt7615_mac_reset_counters(struct mt7615_dev *dev);
void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev);
void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable);
void mt7615_mac_sta_poll(struct mt7615_dev *dev);
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta, int pid,

View File

@ -72,7 +72,10 @@ static int mt7615_pci_probe(struct pci_dev *pdev,
static const struct mt76_driver_ops drv_ops = {
/* txwi_size = txd size + txp size */
.txwi_size = MT_TXD_SIZE + sizeof(struct mt7615_txp),
.txwi_flags = MT_TXWI_NO_FREE,
.drv_flags = MT_DRV_TXWI_NO_FREE,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
.tx_prepare_skb = mt7615_tx_prepare_skb,
.tx_complete_skb = mt7615_tx_complete_skb,
.rx_skb = mt7615_queue_rx_skb,

View File

@ -6,6 +6,8 @@
#define MT_HW_REV 0x1000
#define MT_HW_CHIPID 0x1008
#define MT_TOP_STRAP_STA 0x1010
#define MT_TOP_3NSS BIT(24)
#define MT_TOP_MISC2 0x1134
#define MT_TOP_MISC2_FW_STATE GENMASK(2, 0)
@ -65,6 +67,17 @@
#define MT_WPDMA_ABT_CFG MT_HIF(0x530)
#define MT_WPDMA_ABT_CFG1 MT_HIF(0x534)
#define MT_PLE_BASE 0x8000
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4)
#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8)
#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc)
#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \
((n) << 2))
#define MT_WF_PHY_BASE 0x10000
#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))
@ -125,6 +138,10 @@
MT_AGG_ARxCR_LIMIT_SHIFT(_n), \
MT_AGG_ARxCR_LIMIT_SHIFT(_n))
#define MT_AGG_ASRCR0 MT_WF_AGG(0x060)
#define MT_AGG_ASRCR1 MT_WF_AGG(0x064)
#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0))
#define MT_AGG_ACR0 MT_WF_AGG(0x070)
#define MT_AGG_ACR1 MT_WF_AGG(0x170)
#define MT_AGG_ACR_NO_BA_RULE BIT(0)
@ -176,6 +193,22 @@
#define MT_WF_RFCR_DROP_NDPA BIT(20)
#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21)
#define MT_WF_RFCR1 MT_WF_RMAC(0x004)
#define MT_WF_RFCR1_DROP_ACK BIT(4)
#define MT_WF_RFCR1_DROP_BF_POLL BIT(5)
#define MT_WF_RFCR1_DROP_BA BIT(6)
#define MT_WF_RFCR1_DROP_CFEND BIT(7)
#define MT_WF_RFCR1_DROP_CFACK BIT(8)
#define MT_WF_RMAC_MIB_TIME0 MT_WF_RMAC(0x03c4)
#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)
#define MT_WF_RMAC_MIB_AIRTIME0 MT_WF_RMAC(0x0380)
#define MT_WF_RMAC_MIB_TIME5 MT_WF_RMAC(0x03d8)
#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0)
#define MT_WF_DMA_BASE 0x21800
#define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs))
@ -183,6 +216,15 @@
#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 2)
#define MT_DMA_DCR0_RX_VEC_DROP BIT(17)
#define MT_DMA_BN0RCFR0 MT_WF_DMA(0x070)
#define MT_DMA_BN1RCFR0 MT_WF_DMA(0x0b0)
#define MT_DMA_RCFR0_MCU_RX_MGMT BIT(2)
#define MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR BIT(3)
#define MT_DMA_RCFR0_MCU_RX_CTL_BAR BIT(4)
#define MT_DMA_RCFR0_MCU_RX_BYPASS BIT(21)
#define MT_DMA_RCFR0_RX_DROPPED_UCAST GENMASK(25, 24)
#define MT_DMA_RCFR0_RX_DROPPED_MCAST GENMASK(27, 26)
#define MT_WTBL_BASE 0x30000
#define MT_WTBL_ENTRY_SIZE 256
@ -198,6 +240,7 @@
#define MT_WTBL_UPDATE MT_WTBL_OFF(0x030)
#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(7, 0)
#define MT_WTBL_UPDATE_RXINFO_UPDATE BIT(11)
#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12)
#define MT_WTBL_UPDATE_RATE_UPDATE BIT(13)
#define MT_WTBL_UPDATE_TX_COUNT_CLEAR BIT(14)
#define MT_WTBL_UPDATE_BUSY BIT(31)
@ -255,8 +298,18 @@
#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16)
#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0)
#define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9))
#define MT_MIB_BUSY_MASK GENMASK(23, 0)
#define MT_MIB_SDR9(n) MT_WF_MIB(0x02c + ((n) << 9))
#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
#define MT_MIB_SDR16(n) MT_WF_MIB(0x048 + ((n) << 9))
#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
#define MT_MIB_SDR36(n) MT_WF_MIB(0x098 + ((n) << 9))
#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
#define MT_MIB_SDR37(n) MT_WF_MIB(0x09c + ((n) << 9))
#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
#define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2))
#define MT_EFUSE_BASE 0x81070000
#define MT_EFUSE_BASE_CTRL 0x000

View File

@ -212,7 +212,7 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev,
void mt76x0_get_power_info(struct mt76x02_dev *dev,
struct ieee80211_channel *chan, s8 *tp)
{
struct mt76x0_chan_map {
static const struct mt76x0_chan_map {
u8 chan;
u8 offset;
} chan_map[] = {
@ -343,6 +343,7 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev)
version, fae);
mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR);
mt76_eeprom_override(&dev->mt76);
mt76x0_set_chip_cap(dev);
mt76x0_set_freq_offset(dev);
mt76x0_set_temp_offset(dev);

View File

@ -150,31 +150,6 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev)
mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201);
}
static void mt76x0_reset_counters(struct mt76x02_dev *dev)
{
mt76_rr(dev, MT_RX_STAT_0);
mt76_rr(dev, MT_RX_STAT_1);
mt76_rr(dev, MT_RX_STAT_2);
mt76_rr(dev, MT_TX_STA_0);
mt76_rr(dev, MT_TX_STA_1);
mt76_rr(dev, MT_TX_STA_2);
}
int mt76x0_mac_start(struct mt76x02_dev *dev)
{
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
return -ETIMEDOUT;
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0;
}
EXPORT_SYMBOL_GPL(mt76x0_mac_start);
void mt76x0_mac_stop(struct mt76x02_dev *dev)
{
int i = 200, ok = 0;
@ -244,8 +219,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev)
for (i = 0; i < 256; i++)
mt76x02_mac_wcid_setup(dev, i, 0, NULL);
mt76x0_reset_counters(dev);
ret = mt76x0_eeprom_init(dev);
if (ret)
return ret;

View File

@ -13,19 +13,16 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
{
cancel_delayed_work_sync(&dev->cal_work);
mt76x02_pre_tbtt_enable(dev, false);
if (mt76_is_mmio(dev))
if (mt76_is_mmio(&dev->mt76))
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
mt76_set_channel(&dev->mt76);
mt76x0_phy_set_channel(dev, chandef);
/* channel cycle counters read-and-clear */
mt76_rr(dev, MT_CH_IDLE);
mt76_rr(dev, MT_CH_BUSY);
mt76x02_mac_cc_reset(dev);
mt76x02_edcca_init(dev);
if (mt76_is_mmio(dev)) {
if (mt76_is_mmio(&dev->mt76)) {
mt76x02_dfs_init_params(dev);
tasklet_enable(&dev->dfs_pd.dfs_tasklet);
}

View File

@ -30,7 +30,7 @@
static inline bool is_mt7610e(struct mt76x02_dev *dev)
{
if (!mt76_is_mmio(dev))
if (!mt76_is_mmio(&dev->mt76))
return false;
return mt76_chip(&dev->mt76) == 0x7610;
@ -46,7 +46,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev);
int mt76x0_register_device(struct mt76x02_dev *dev);
void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset);
int mt76x0_mac_start(struct mt76x02_dev *dev);
void mt76x0_mac_stop(struct mt76x02_dev *dev);
int mt76x0_config(struct ieee80211_hw *hw, u32 changed);

View File

@ -51,19 +51,6 @@ static void mt76x0e_stop(struct ieee80211_hw *hw)
mt76x0e_stop_hw(dev);
}
static int
mt76x0e_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct mt76x02_dev *dev = hw->priv;
if (is_mt7630(dev))
return -EOPNOTSUPP;
return mt76x02_set_key(hw, cmd, vif, sta, key);
}
static void
mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
@ -80,7 +67,7 @@ static const struct ieee80211_ops mt76x0e_ops = {
.configure_filter = mt76x02_configure_filter,
.bss_info_changed = mt76x02_bss_info_changed,
.sta_state = mt76_sta_state,
.set_key = mt76x0e_set_key,
.set_key = mt76x02_set_key,
.conf_tx = mt76x02_conf_tx,
.sw_scan_start = mt76_sw_scan,
.sw_scan_complete = mt76x02_sw_scan_complete,
@ -94,6 +81,7 @@ static const struct ieee80211_ops mt76x0e_ops = {
.release_buffered_frames = mt76_release_buffered_frames,
.set_coverage_class = mt76x02_set_coverage_class,
.set_rts_threshold = mt76x02_set_rts_threshold,
.get_antenna = mt76_get_antenna,
};
static int mt76x0e_register_device(struct mt76x02_dev *dev)
@ -132,15 +120,6 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev)
mt76_clear(dev, 0x110, BIT(9));
mt76_set(dev, MT_MAX_LEN_CFG, BIT(13));
mt76_wr(dev, MT_CH_TIME_CFG,
MT_CH_TIME_CFG_TIMER_EN |
MT_CH_TIME_CFG_TX_AS_BUSY |
MT_CH_TIME_CFG_RX_AS_BUSY |
MT_CH_TIME_CFG_NAV_AS_BUSY |
MT_CH_TIME_CFG_EIFS_AS_BUSY |
MT_CH_CCA_RC_EN |
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
err = mt76x0_register_device(dev);
if (err < 0)
return err;
@ -155,7 +134,9 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct mt76_driver_ops drv_ops = {
.txwi_size = sizeof(struct mt76x02_txwi),
.tx_aligned4_skbs = true,
.drv_flags = MT_DRV_TX_ALIGNED4_SKBS |
MT_DRV_SW_RX_AIRTIME,
.survey_flags = SURVEY_INFO_TIME_TX,
.update_survey = mt76x02_update_channel,
.tx_prepare_skb = mt76x02_tx_prepare_skb,
.tx_complete_skb = mt76x02_tx_complete_skb,

View File

@ -102,7 +102,7 @@ out:
static int
mt76x0_rf_wr(struct mt76x02_dev *dev, u32 offset, u8 val)
{
if (mt76_is_usb(dev)) {
if (mt76_is_usb(&dev->mt76)) {
struct mt76_reg_pair pair = {
.reg = offset,
.value = val,
@ -121,7 +121,7 @@ static int mt76x0_rf_rr(struct mt76x02_dev *dev, u32 offset)
int ret;
u32 val;
if (mt76_is_usb(dev)) {
if (mt76_is_usb(&dev->mt76)) {
struct mt76_reg_pair pair = {
.reg = offset,
};
@ -176,7 +176,7 @@ mt76x0_phy_rf_csr_wr_rp(struct mt76x02_dev *dev,
}
#define RF_RANDOM_WRITE(dev, tab) do { \
if (mt76_is_mmio(dev)) \
if (mt76_is_mmio(&dev->mt76)) \
mt76x0_phy_rf_csr_wr_rp(dev, tab, ARRAY_SIZE(tab)); \
else \
mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));\
@ -744,7 +744,7 @@ mt76x0_phy_get_delta_power(struct mt76x02_dev *dev, u8 tx_mode,
if (!tx_mode) {
data = mt76_rr(dev, MT_BBP(CORE, 1));
if (is_mt7630(dev) && mt76_is_mmio(dev)) {
if (is_mt7630(dev) && mt76_is_mmio(&dev->mt76)) {
int offset;
/* 2.3 * 8192 or 1.5 * 8192 */
@ -899,7 +899,6 @@ void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on)
}
mt76x02_mcu_calibrate(dev, MCU_CAL_FULL, val);
msleep(350);
mt76x02_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz);
usleep_range(15000, 20000);
@ -967,7 +966,7 @@ void mt76x0_phy_set_channel(struct mt76x02_dev *dev,
break;
}
if (mt76_is_usb(dev)) {
if (mt76_is_usb(&dev->mt76)) {
mt76x0_phy_bbp_set_bw(dev, chandef->width);
} else {
if (chandef->width == NL80211_CHAN_WIDTH_80 ||
@ -1123,7 +1122,7 @@ static void mt76x0_rf_patch_reg_array(struct mt76x02_dev *dev,
switch (reg) {
case MT_RF(0, 3):
if (mt76_is_mmio(dev)) {
if (mt76_is_mmio(&dev->mt76)) {
if (is_mt7630(dev))
val = 0x70;
else

View File

@ -103,7 +103,7 @@ static int mt76x0u_start(struct ieee80211_hw *hw)
struct mt76x02_dev *dev = hw->priv;
int ret;
ret = mt76x0_mac_start(dev);
ret = mt76x02u_mac_start(dev);
if (ret)
return ret;
@ -138,6 +138,7 @@ static const struct ieee80211_ops mt76x0u_ops = {
.get_survey = mt76_get_survey,
.set_tim = mt76_set_tim,
.release_buffered_frames = mt76_release_buffered_frames,
.get_antenna = mt76_get_antenna,
};
static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset)
@ -165,13 +166,6 @@ static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset)
FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
mt76_wr(dev, MT_CH_TIME_CFG,
MT_CH_TIME_CFG_TIMER_EN |
MT_CH_TIME_CFG_TX_AS_BUSY |
MT_CH_TIME_CFG_RX_AS_BUSY |
MT_CH_TIME_CFG_NAV_AS_BUSY |
MT_CH_TIME_CFG_EIFS_AS_BUSY);
return 0;
}
@ -211,6 +205,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
const struct usb_device_id *id)
{
static const struct mt76_driver_ops drv_ops = {
.drv_flags = MT_DRV_SW_RX_AIRTIME,
.survey_flags = SURVEY_INFO_TIME_TX,
.update_survey = mt76x02_update_channel,
.tx_prepare_skb = mt76x02u_tx_prepare_skb,
.tx_complete_skb = mt76x02u_tx_complete_skb,
@ -226,7 +222,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
u32 mac_rev;
int ret;
mdev = mt76_alloc_device(&usb_dev->dev, sizeof(*dev), &mt76x0u_ops,
mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), &mt76x0u_ops,
&drv_ops);
if (!mdev)
return -ENOMEM;
@ -278,6 +274,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
err:
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
mt76u_deinit(&dev->mt76);
ieee80211_free_hw(mdev->hw);
return ret;
@ -297,6 +294,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf)
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
mt76u_deinit(&dev->mt76);
ieee80211_free_hw(dev->mt76.hw);
}

View File

@ -81,6 +81,7 @@ struct mt76x02_dev {
u8 txdone_seq;
DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status);
spinlock_t txstatus_fifo_lock;
u32 tx_airtime;
struct sk_buff *rx_head;
@ -92,8 +93,6 @@ struct mt76x02_dev {
const struct mt76x02_beacon_ops *beacon_ops;
u32 aggr_stats[32];
struct sk_buff *beacons[8];
u8 beacon_data_mask;

View File

@ -19,7 +19,8 @@ mt76x02_ampdu_stat_read(struct seq_file *file, void *data)
seq_puts(file, "\n");
seq_puts(file, "Count: ");
for (j = 0; j < 8; j++)
seq_printf(file, "%8d | ", dev->aggr_stats[i * 8 + j]);
seq_printf(file, "%8d | ",
dev->mt76.aggr_stats[i * 8 + j]);
seq_puts(file, "\n");
seq_puts(file, "--------");
for (j = 0; j < 8; j++)
@ -143,6 +144,8 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev)
if (!dir)
return;
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
mt76_queues_read);
debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp);
debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc);

View File

@ -7,6 +7,27 @@
#include "mt76x02.h"
#include "mt76x02_trace.h"
void mt76x02_mac_reset_counters(struct mt76x02_dev *dev)
{
int i;
mt76_rr(dev, MT_RX_STAT_0);
mt76_rr(dev, MT_RX_STAT_1);
mt76_rr(dev, MT_RX_STAT_2);
mt76_rr(dev, MT_TX_STA_0);
mt76_rr(dev, MT_TX_STA_1);
mt76_rr(dev, MT_TX_STA_2);
for (i = 0; i < 16; i++)
mt76_rr(dev, MT_TX_AGG_CNT(i));
for (i = 0; i < 16; i++)
mt76_rr(dev, MT_TX_STAT_FIFO);
memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
}
EXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters);
static enum mt76x02_cipher_type
mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
{
@ -462,8 +483,8 @@ mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta,
phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
if (st->pktid & MT_PACKET_ID_HAS_RATE) {
first_rate = st->rate & ~MT_RXWI_RATE_INDEX;
first_rate |= st->pktid & MT_RXWI_RATE_INDEX;
first_rate = st->rate & ~MT_PKTID_RATE;
first_rate |= st->pktid & MT_PKTID_RATE;
mt76x02_mac_process_tx_rate(&rate[0], first_rate,
dev->mt76.chandef.chan->band);
@ -516,10 +537,20 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
struct ieee80211_tx_status status = {
.info = &info
};
static const u8 ac_to_tid[4] = {
[IEEE80211_AC_BE] = 0,
[IEEE80211_AC_BK] = 1,
[IEEE80211_AC_VI] = 4,
[IEEE80211_AC_VO] = 6
};
struct mt76_wcid *wcid = NULL;
struct mt76x02_sta *msta = NULL;
struct mt76_dev *mdev = &dev->mt76;
struct sk_buff_head list;
u32 duration = 0;
u8 cur_pktid;
u32 ac = 0;
int len = 0;
if (stat->pktid == MT_PACKET_ID_NO_ACK)
return;
@ -549,10 +580,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) {
mt76_tx_status_unlock(mdev, &list);
rcu_read_unlock();
return;
goto out;
}
if (msta && stat->aggr && !status.skb) {
u32 stat_val, stat_cache;
@ -565,10 +596,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
stat->wcid == msta->status.wcid && msta->n_frames < 32) {
msta->n_frames++;
mt76_tx_status_unlock(mdev, &list);
rcu_read_unlock();
return;
goto out;
}
cur_pktid = msta->status.pktid;
mt76x02_mac_fill_tx_status(dev, msta, status.info,
&msta->status, msta->n_frames);
@ -576,16 +607,39 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
msta->n_frames = 1;
*update = 0;
} else {
cur_pktid = stat->pktid;
mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1);
*update = 1;
}
if (status.skb)
if (status.skb) {
info = *status.info;
len = status.skb->len;
ac = skb_get_queue_mapping(status.skb);
mt76_tx_status_skb_done(mdev, status.skb, &list);
} else if (msta) {
len = status.info->status.ampdu_len * ewma_pktlen_read(&msta->pktlen);
ac = FIELD_GET(MT_PKTID_AC, cur_pktid);
}
mt76_tx_status_unlock(mdev, &list);
if (!status.skb)
ieee80211_tx_status_ext(mt76_hw(dev), &status);
if (!len)
goto out;
duration = mt76_calc_tx_airtime(&dev->mt76, &info, len);
spin_lock_bh(&dev->mt76.cc_lock);
dev->tx_airtime += duration;
spin_unlock_bh(&dev->mt76.cc_lock);
if (msta)
ieee80211_sta_register_airtime(status.sta, ac_to_tid[ac], duration, 0);
out:
rcu_read_unlock();
}
@ -768,6 +822,21 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL))
status->aggr = true;
if (rxinfo & MT_RXINFO_AMPDU) {
status->flag |= RX_FLAG_AMPDU_DETAILS;
status->ampdu_ref = dev->mt76.ampdu_ref;
/*
* When receiving an A-MPDU subframe and RSSI info is not valid,
* we can assume that more subframes belonging to the same A-MPDU
* are coming. The last one will have valid RSSI info
*/
if (rxinfo & MT_RXINFO_RSSI) {
if (!++dev->mt76.ampdu_ref)
dev->mt76.ampdu_ref++;
}
}
if (WARN_ON_ONCE(len > skb->len))
return -EINVAL;
@ -948,16 +1017,13 @@ void mt76x02_update_channel(struct mt76_dev *mdev)
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
struct mt76_channel_state *state;
u32 active, busy;
state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan);
busy = mt76_rr(dev, MT_CH_BUSY);
active = busy + mt76_rr(dev, MT_CH_IDLE);
state = mdev->chan_state;
state->cc_busy += mt76_rr(dev, MT_CH_BUSY);
spin_lock_bh(&dev->mt76.cc_lock);
state->cc_busy += busy;
state->cc_active += active;
state->cc_tx += dev->tx_airtime;
dev->tx_airtime = 0;
spin_unlock_bh(&dev->mt76.cc_lock);
}
EXPORT_SYMBOL_GPL(mt76x02_update_channel);
@ -1094,12 +1160,12 @@ void mt76x02_mac_work(struct work_struct *work)
mutex_lock(&dev->mt76.mutex);
mt76x02_update_channel(&dev->mt76);
mt76_update_survey(&dev->mt76);
for (i = 0, idx = 0; i < 16; i++) {
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
dev->aggr_stats[idx++] += val & 0xffff;
dev->aggr_stats[idx++] += val >> 16;
dev->mt76.aggr_stats[idx++] += val & 0xffff;
dev->mt76.aggr_stats[idx++] += val >> 16;
}
if (!dev->mt76.beacon_mask)
@ -1116,6 +1182,25 @@ void mt76x02_mac_work(struct work_struct *work)
MT_MAC_WORK_INTERVAL);
}
void mt76x02_mac_cc_reset(struct mt76x02_dev *dev)
{
dev->mt76.survey_time = ktime_get_boottime();
mt76_wr(dev, MT_CH_TIME_CFG,
MT_CH_TIME_CFG_TIMER_EN |
MT_CH_TIME_CFG_TX_AS_BUSY |
MT_CH_TIME_CFG_RX_AS_BUSY |
MT_CH_TIME_CFG_NAV_AS_BUSY |
MT_CH_TIME_CFG_EIFS_AS_BUSY |
MT_CH_CCA_RC_EN |
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
/* channel cycle counters read-and-clear */
mt76_rr(dev, MT_CH_BUSY);
mt76_rr(dev, MT_CH_IDLE);
}
EXPORT_SYMBOL_GPL(mt76x02_mac_cc_reset);
void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
{
idx &= 7;

View File

@ -23,11 +23,16 @@ struct mt76x02_tx_status {
#define MT_VIF_WCID(_n) (254 - ((_n) & 7))
#define MT_MAX_VIFS 8
#define MT_PKTID_RATE GENMASK(4, 0)
#define MT_PKTID_AC GENMASK(6, 5)
struct mt76x02_vif {
struct mt76_wcid group_wcid; /* must be first */
u8 idx;
};
DECLARE_EWMA(pktlen, 8, 8);
struct mt76x02_sta {
struct mt76_wcid wcid; /* must be first */
@ -35,6 +40,7 @@ struct mt76x02_sta {
struct mt76x02_tx_status status;
int n_frames;
struct ewma_pktlen pktlen;
};
#define MT_RXINFO_BA BIT(0)
@ -161,6 +167,7 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev)
return false;
}
void mt76x02_mac_reset_counters(struct mt76x02_dev *dev);
void mt76x02_mac_set_short_preamble(struct mt76x02_dev *dev, bool enable);
int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
u8 key_idx, struct ieee80211_key_conf *key);
@ -192,6 +199,7 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
void mt76x02_update_channel(struct mt76_dev *mdev);
void mt76x02_mac_work(struct work_struct *work);
void mt76x02_mac_cc_reset(struct mt76x02_dev *dev);
void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr);
int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
struct sk_buff *skb);

View File

@ -114,7 +114,7 @@ int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param)
.id = cpu_to_le32(type),
.value = cpu_to_le32(param),
};
bool is_mt76x2e = mt76_is_mmio(dev) && is_mt76x2(dev);
bool is_mt76x2e = mt76_is_mmio(&dev->mt76) && is_mt76x2(dev);
int ret;
if (is_mt76x2e)

View File

@ -343,6 +343,7 @@ EXPORT_SYMBOL_GPL(mt76x02_dma_disable);
void mt76x02_mac_start(struct mt76x02_dev *dev)
{
mt76x02_mac_reset_counters(dev);
mt76x02_dma_enable(dev);
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
mt76_wr(dev, MT_MAC_SYS_CTRL,

View File

@ -158,7 +158,9 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
/* encode packet rate for no-skb packet id to fix up status reporting */
if (pid == MT_PACKET_ID_NO_SKB)
pid = MT_PACKET_ID_HAS_RATE |
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX) |
FIELD_PREP(MT_PKTID_AC,
skb_get_queue_mapping(tx_info->skb));
txwi->pktid = pid;
@ -171,6 +173,12 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
tx_info->info |= MT_TXD_INFO_WIV;
if (sta) {
struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
ewma_pktlen_add(&msta->pktlen, tx_info->skb->len);
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_tx_prepare_skb);

View File

@ -8,6 +8,7 @@
#include "mt76x02.h"
int mt76x02u_mac_start(struct mt76x02_dev *dev);
void mt76x02u_init_mcu(struct mt76_dev *dev);
void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev);
int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data,

View File

@ -23,6 +23,27 @@ void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
}
EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb);
int mt76x02u_mac_start(struct mt76x02_dev *dev)
{
mt76x02_mac_reset_counters(dev);
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
return -ETIMEDOUT;
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX |
MT_MAC_SYS_CTRL_ENABLE_RX);
if (!mt76x02_wait_for_wpdma(&dev->mt76, 50))
return -ETIMEDOUT;
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02u_mac_start);
int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
{
struct sk_buff *iter, *last = skb;
@ -83,7 +104,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
/* encode packet rate for no-skb packet id to fix up status reporting */
if (pid == MT_PACKET_ID_NO_SKB)
pid = MT_PACKET_ID_HAS_RATE |
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
(le16_to_cpu(txwi->rate) & MT_PKTID_RATE) |
FIELD_PREP(MT_PKTID_AC,
skb_get_queue_mapping(tx_info->skb));
txwi->pktid = pid;
@ -97,6 +120,12 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
flags |= MT_TXD_INFO_WIV;
if (sta) {
struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
ewma_pktlen_add(&msta->pktlen, tx_info->skb->len);
}
return mt76x02u_skb_dma_info(tx_info->skb, WLAN_PORT, flags);
}
EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb);

View File

@ -153,15 +153,7 @@ void mt76x02_init_device(struct mt76x02_dev *dev)
hw->max_rate_tries = 1;
hw->extra_tx_headroom = 2;
wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_ADHOC);
if (mt76_is_usb(dev)) {
if (mt76_is_usb(&dev->mt76)) {
hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) +
MT_DMA_HDR_LEN;
wiphy->iface_combinations = mt76x02u_if_comb;
@ -190,7 +182,6 @@ void mt76x02_init_device(struct mt76x02_dev *dev)
hw->vif_data_size = sizeof(struct mt76x02_vif);
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
dev->mt76.global_wcid.idx = 255;
dev->mt76.global_wcid.hw_key_idx = -1;
@ -264,6 +255,7 @@ int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
msta->wcid.hw_key_idx = -1;
mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
mt76x02_mac_wcid_set_drop(dev, idx, false);
ewma_pktlen_init(&msta->pktlen);
if (vif->type == NL80211_IFTYPE_AP)
set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
@ -365,12 +357,14 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 tid = params->tid;
u16 ssn = params->ssn;
struct mt76_txq *mtxq;
int ret = 0;
if (!txq)
return -EINVAL;
mtxq = (struct mt76_txq *)txq->drv_priv;
mutex_lock(&dev->mt76.mutex);
switch (action) {
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid,
@ -393,14 +387,16 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
break;
case IEEE80211_AMPDU_TX_START:
mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
return IEEE80211_AMPDU_TX_START_IMMEDIATE;
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
mutex_unlock(&dev->mt76.mutex);
return 0;
return ret;
}
EXPORT_SYMBOL_GPL(mt76x02_ampdu_action);
@ -442,7 +438,7 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* data registers and sent via HW beacons engine, they require to
* be already encrypted.
*/
if (mt76_is_usb(dev) &&
if (mt76_is_usb(&dev->mt76) &&
vif->type == NL80211_IFTYPE_AP &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;
@ -623,7 +619,7 @@ void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta,
int idx = msta->wcid.idx;
mt76_stop_tx_queues(&dev->mt76, sta, true);
if (mt76_is_mmio(dev))
if (mt76_is_mmio(mdev))
mt76x02_mac_wcid_set_drop(dev, idx, ps);
}
EXPORT_SYMBOL_GPL(mt76x02_sta_ps);

View File

@ -12,7 +12,6 @@ struct mt76x02_dev;
struct mt76x2_sta;
struct mt76x02_vif;
int mt76x2_mac_start(struct mt76x02_dev *dev);
void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force);
static inline void mt76x2_mac_resume(struct mt76x02_dev *dev)

View File

@ -24,7 +24,6 @@ void mt76x2u_cleanup(struct mt76x02_dev *dev);
void mt76x2u_stop_hw(struct mt76x02_dev *dev);
int mt76x2u_mac_reset(struct mt76x02_dev *dev);
int mt76x2u_mac_start(struct mt76x02_dev *dev);
int mt76x2u_mac_stop(struct mt76x02_dev *dev);
int mt76x2u_phy_set_channel(struct mt76x02_dev *dev,

View File

@ -21,7 +21,9 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct mt76_driver_ops drv_ops = {
.txwi_size = sizeof(struct mt76x02_txwi),
.tx_aligned4_skbs = true,
.drv_flags = MT_DRV_TX_ALIGNED4_SKBS |
MT_DRV_SW_RX_AIRTIME,
.survey_flags = SURVEY_INFO_TIME_TX,
.update_survey = mt76x02_update_channel,
.tx_prepare_skb = mt76x02_tx_prepare_skb,
.tx_complete_skb = mt76x02_tx_complete_skb,

View File

@ -7,6 +7,7 @@
#include "mt76x2.h"
#include "eeprom.h"
#include "mcu.h"
#include "../mt76x02_mac.h"
static void
mt76x2_mac_pbf_init(struct mt76x02_dev *dev)
@ -132,36 +133,11 @@ int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
for (i = 0; i < 16; i++)
mt76_rr(dev, MT_TX_STAT_FIFO);
mt76_wr(dev, MT_CH_TIME_CFG,
MT_CH_TIME_CFG_TIMER_EN |
MT_CH_TIME_CFG_TX_AS_BUSY |
MT_CH_TIME_CFG_RX_AS_BUSY |
MT_CH_TIME_CFG_NAV_AS_BUSY |
MT_CH_TIME_CFG_EIFS_AS_BUSY |
MT_CH_CCA_RC_EN |
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
mt76x02_set_tx_ackto(dev);
return 0;
}
int mt76x2_mac_start(struct mt76x02_dev *dev)
{
int i;
for (i = 0; i < 16; i++)
mt76_rr(dev, MT_TX_AGG_CNT(i));
for (i = 0; i < 16; i++)
mt76_rr(dev, MT_TX_STAT_FIFO);
memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats));
mt76x02_mac_start(dev);
return 0;
}
static void
mt76x2_power_on_rf_patch(struct mt76x02_dev *dev)
{
@ -264,9 +240,7 @@ static int mt76x2_init_hardware(struct mt76x02_dev *dev)
return ret;
set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
ret = mt76x2_mac_start(dev);
if (ret)
return ret;
mt76x02_mac_start(dev);
ret = mt76x2_mcu_init(dev);
if (ret)

View File

@ -4,6 +4,7 @@
*/
#include "mt76x2.h"
#include "../mt76x02_mac.h"
static int
mt76x2_start(struct ieee80211_hw *hw)
@ -11,10 +12,7 @@ mt76x2_start(struct ieee80211_hw *hw)
struct mt76x02_dev *dev = hw->priv;
int ret;
ret = mt76x2_mac_start(dev);
if (ret)
return ret;
mt76x02_mac_start(dev);
ret = mt76x2_phy_start(dev);
if (ret)
return ret;
@ -54,10 +52,7 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
mt76x2_mac_stop(dev, true);
ret = mt76x2_phy_set_channel(dev, chandef);
/* channel cycle counters read-and-clear */
mt76_rr(dev, MT_CH_IDLE);
mt76_rr(dev, MT_CH_BUSY);
mt76x02_mac_cc_reset(dev);
mt76x02_dfs_init_params(dev);
mt76x2_mac_resume(dev);
@ -140,19 +135,6 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
return 0;
}
static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
u32 *rx_ant)
{
struct mt76x02_dev *dev = hw->priv;
mutex_lock(&dev->mt76.mutex);
*tx_ant = dev->mt76.antenna_mask;
*rx_ant = dev->mt76.antenna_mask;
mutex_unlock(&dev->mt76.mutex);
return 0;
}
const struct ieee80211_ops mt76x2_ops = {
.tx = mt76x02_tx,
.start = mt76x2_start,
@ -177,7 +159,7 @@ const struct ieee80211_ops mt76x2_ops = {
.get_survey = mt76_get_survey,
.set_tim = mt76_set_tim,
.set_antenna = mt76x2_set_antenna,
.get_antenna = mt76x2_get_antenna,
.get_antenna = mt76_get_antenna,
.set_rts_threshold = mt76x02_set_rts_threshold,
};

View File

@ -25,6 +25,8 @@ static int mt76x2u_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
static const struct mt76_driver_ops drv_ops = {
.drv_flags = MT_DRV_SW_RX_AIRTIME,
.survey_flags = SURVEY_INFO_TIME_TX,
.update_survey = mt76x02_update_channel,
.tx_prepare_skb = mt76x02u_tx_prepare_skb,
.tx_complete_skb = mt76x02u_tx_complete_skb,
@ -39,7 +41,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
struct mt76_dev *mdev;
int err;
mdev = mt76_alloc_device(&udev->dev, sizeof(*dev), &mt76x2u_ops,
mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops,
&drv_ops);
if (!mdev)
return -ENOMEM;
@ -71,6 +73,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
err:
ieee80211_free_hw(mt76_hw(dev));
mt76u_deinit(&dev->mt76);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
@ -86,6 +89,7 @@ static void mt76x2u_disconnect(struct usb_interface *intf)
set_bit(MT76_REMOVED, &dev->mt76.state);
ieee80211_unregister_hw(hw);
mt76x2u_cleanup(dev);
mt76u_deinit(&dev->mt76);
ieee80211_free_hw(hw);
usb_set_intfdata(intf, NULL);

View File

@ -184,13 +184,6 @@ int mt76x2u_init_hardware(struct mt76x02_dev *dev)
mt76x02_phy_set_rxpath(dev);
mt76x02_phy_set_txdac(dev);
mt76_wr(dev, MT_CH_TIME_CFG,
MT_CH_TIME_CFG_TIMER_EN |
MT_CH_TIME_CFG_TX_AS_BUSY |
MT_CH_TIME_CFG_RX_AS_BUSY |
MT_CH_TIME_CFG_NAV_AS_BUSY |
MT_CH_TIME_CFG_EIFS_AS_BUSY);
return mt76x2u_mac_stop(dev);
}

View File

@ -6,16 +6,6 @@
#include "mt76x2u.h"
#include "eeprom.h"
static void mt76x2u_mac_reset_counters(struct mt76x02_dev *dev)
{
mt76_rr(dev, MT_RX_STAT_0);
mt76_rr(dev, MT_RX_STAT_1);
mt76_rr(dev, MT_RX_STAT_2);
mt76_rr(dev, MT_TX_STA_0);
mt76_rr(dev, MT_TX_STA_1);
mt76_rr(dev, MT_TX_STA_2);
}
static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev)
{
s8 offset = 0;
@ -102,23 +92,6 @@ int mt76x2u_mac_reset(struct mt76x02_dev *dev)
return 0;
}
int mt76x2u_mac_start(struct mt76x02_dev *dev)
{
mt76x2u_mac_reset_counters(dev);
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
mt76x02_wait_for_wpdma(&dev->mt76, 1000);
usleep_range(50, 100);
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX |
MT_MAC_SYS_CTRL_ENABLE_RX);
return 0;
}
int mt76x2u_mac_stop(struct mt76x02_dev *dev)
{
int i, count = 0, val;

View File

@ -4,13 +4,14 @@
*/
#include "mt76x2u.h"
#include "../mt76x02_usb.h"
static int mt76x2u_start(struct ieee80211_hw *hw)
{
struct mt76x02_dev *dev = hw->priv;
int ret;
ret = mt76x2u_mac_start(dev);
ret = mt76x02u_mac_start(dev);
if (ret)
return ret;
@ -48,10 +49,7 @@ mt76x2u_set_channel(struct mt76x02_dev *dev,
err = mt76x2u_phy_set_channel(dev, chandef);
/* channel cycle counters read-and-clear */
mt76_rr(dev, MT_CH_IDLE);
mt76_rr(dev, MT_CH_BUSY);
mt76x02_mac_cc_reset(dev);
mt76x2_mac_resume(dev);
clear_bit(MT76_RESET, &dev->mt76.state);
@ -121,4 +119,5 @@ const struct ieee80211_ops mt76x2u_ops = {
.get_survey = mt76_get_survey,
.set_tim = mt76_set_tim,
.release_buffered_frames = mt76_release_buffered_frames,
.get_antenna = mt76_get_antenna,
};

View File

@ -378,7 +378,7 @@ EXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
static int
mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq,
struct mt76_txq *mtxq, bool *empty)
struct mt76_txq *mtxq)
{
struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
enum mt76_txq_id qid = mt76_txq_get_qid(txq);
@ -392,16 +392,12 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq,
bool probe;
int idx;
if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) {
*empty = true;
if (test_bit(MT_WCID_FLAG_PS, &wcid->flags))
return 0;
}
skb = mt76_txq_dequeue(dev, mtxq, false);
if (!skb) {
*empty = true;
if (!skb)
return 0;
}
info = IEEE80211_SKB_CB(skb);
if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
@ -431,10 +427,8 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq,
return -EBUSY;
skb = mt76_txq_dequeue(dev, mtxq, false);
if (!skb) {
*empty = true;
if (!skb)
break;
}
info = IEEE80211_SKB_CB(skb);
cur_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
@ -481,8 +475,6 @@ mt76_txq_schedule_list(struct mt76_dev *dev, enum mt76_txq_id qid)
spin_lock_bh(&hwq->lock);
while (1) {
bool empty = false;
if (sq->swq_queued >= 4)
break;
@ -513,10 +505,9 @@ mt76_txq_schedule_list(struct mt76_dev *dev, enum mt76_txq_id qid)
spin_lock_bh(&hwq->lock);
}
ret += mt76_txq_send_burst(dev, sq, mtxq, &empty);
if (skb_queue_empty(&mtxq->retry_q))
empty = true;
ieee80211_return_txq(dev->hw, txq, !empty);
ret += mt76_txq_send_burst(dev, sq, mtxq);
ieee80211_return_txq(dev->hw, txq,
!skb_queue_empty(&mtxq->retry_q));
}
spin_unlock_bh(&hwq->lock);

View File

@ -15,15 +15,17 @@ static bool disable_usb_sg;
module_param_named(disable_usb_sg, disable_usb_sg, bool, 0644);
MODULE_PARM_DESC(disable_usb_sg, "Disable usb scatter-gather support");
/* should be called with usb_ctrl_mtx locked */
static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req,
u8 req_type, u16 val, u16 offset,
void *buf, size_t len)
{
struct usb_device *udev = to_usb_device(dev->dev);
struct usb_interface *uintf = to_usb_interface(dev->dev);
struct usb_device *udev = interface_to_usbdev(uintf);
unsigned int pipe;
int i, ret;
lockdep_assert_held(&dev->usb.usb_ctrl_mtx);
pipe = (req_type & USB_DIR_IN) ? usb_rcvctrlpipe(udev, 0)
: usb_sndctrlpipe(udev, 0);
for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) {
@ -60,7 +62,6 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req,
}
EXPORT_SYMBOL_GPL(mt76u_vendor_request);
/* should be called with usb_ctrl_mtx locked */
static u32 __mt76u_rr(struct mt76_dev *dev, u32 addr)
{
struct mt76_usb *usb = &dev->usb;
@ -103,7 +104,6 @@ static u32 mt76u_rr(struct mt76_dev *dev, u32 addr)
return ret;
}
/* should be called with usb_ctrl_mtx locked */
static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val)
{
struct mt76_usb *usb = &dev->usb;
@ -235,7 +235,8 @@ mt76u_rd_rp(struct mt76_dev *dev, u32 base,
static bool mt76u_check_sg(struct mt76_dev *dev)
{
struct usb_device *udev = to_usb_device(dev->dev);
struct usb_interface *uintf = to_usb_interface(dev->dev);
struct usb_device *udev = interface_to_usbdev(uintf);
return (!disable_usb_sg && udev->bus->sg_tablesize > 0 &&
(udev->bus->no_sg_constraint ||
@ -370,7 +371,8 @@ mt76u_fill_bulk_urb(struct mt76_dev *dev, int dir, int index,
struct urb *urb, usb_complete_t complete_fn,
void *context)
{
struct usb_device *udev = to_usb_device(dev->dev);
struct usb_interface *uintf = to_usb_interface(dev->dev);
struct usb_device *udev = interface_to_usbdev(uintf);
unsigned int pipe;
if (dir == USB_DIR_IN)
@ -695,10 +697,7 @@ static void mt76u_tx_tasklet(unsigned long data)
mt76_txq_schedule(dev, i);
if (!test_and_set_bit(MT76_READING_STATS, &dev->state))
ieee80211_queue_delayed_work(dev->hw,
&dev->usb.stat_work,
msecs_to_jiffies(10));
queue_work(dev->usb.stat_wq, &dev->usb.stat_work);
if (wake)
ieee80211_wake_queue(dev->hw, i);
}
@ -711,7 +710,7 @@ static void mt76u_tx_status_data(struct work_struct *work)
u8 update = 1;
u16 count = 0;
usb = container_of(work, struct mt76_usb, stat_work.work);
usb = container_of(work, struct mt76_usb, stat_work);
dev = container_of(usb, struct mt76_dev, usb);
while (true) {
@ -724,8 +723,7 @@ static void mt76u_tx_status_data(struct work_struct *work)
}
if (count && test_bit(MT76_STATE_RUNNING, &dev->state))
ieee80211_queue_delayed_work(dev->hw, &usb->stat_work,
msecs_to_jiffies(10));
queue_work(usb->stat_wq, &usb->stat_work);
else
clear_bit(MT76_READING_STATS, &dev->state);
}
@ -906,7 +904,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
}
}
cancel_delayed_work_sync(&dev->usb.stat_work);
cancel_work_sync(&dev->usb.stat_work);
clear_bit(MT76_READING_STATS, &dev->state);
mt76_tx_status_check(dev, NULL, true);
@ -952,24 +950,40 @@ int mt76u_init(struct mt76_dev *dev,
.rd_rp = mt76u_rd_rp,
.type = MT76_BUS_USB,
};
struct usb_device *udev = interface_to_usbdev(intf);
struct mt76_usb *usb = &dev->usb;
tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev);
tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev);
INIT_DELAYED_WORK(&usb->stat_work, mt76u_tx_status_data);
INIT_WORK(&usb->stat_work, mt76u_tx_status_data);
skb_queue_head_init(&dev->rx_skb[MT_RXQ_MAIN]);
usb->stat_wq = alloc_workqueue("mt76u", WQ_UNBOUND, 0);
if (!usb->stat_wq)
return -ENOMEM;
mutex_init(&usb->mcu.mutex);
mutex_init(&usb->usb_ctrl_mtx);
dev->bus = &mt76u_ops;
dev->queue_ops = &usb_queue_ops;
dev_set_drvdata(&udev->dev, dev);
usb->sg_en = mt76u_check_sg(dev);
return mt76u_set_endpoints(intf, usb);
}
EXPORT_SYMBOL_GPL(mt76u_init);
void mt76u_deinit(struct mt76_dev *dev)
{
if (dev->usb.stat_wq) {
destroy_workqueue(dev->usb.stat_wq);
dev->usb.stat_wq = NULL;
}
}
EXPORT_SYMBOL_GPL(mt76u_deinit);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -12,6 +12,16 @@
#define QTNF_MAX_MAC 3
#define HBM_FRAME_META_MAGIC_PATTERN_S 0xAB
#define HBM_FRAME_META_MAGIC_PATTERN_E 0xBA
struct qtnf_frame_meta_info {
u8 magic_s;
u8 ifidx;
u8 macid;
u8 magic_e;
} __packed;
enum qtnf_fw_state {
QTNF_FW_STATE_DETACHED,
QTNF_FW_STATE_BOOT_DONE,
@ -31,8 +41,10 @@ struct qtnf_bus_ops {
int (*control_tx)(struct qtnf_bus *, struct sk_buff *);
/* data xfer methods */
int (*data_tx)(struct qtnf_bus *, struct sk_buff *);
int (*data_tx)(struct qtnf_bus *bus, struct sk_buff *skb,
unsigned int macid, unsigned int vifid);
void (*data_tx_timeout)(struct qtnf_bus *, struct net_device *);
void (*data_tx_use_meta_set)(struct qtnf_bus *bus, bool use_meta);
void (*data_rx_start)(struct qtnf_bus *);
void (*data_rx_stop)(struct qtnf_bus *);
};
@ -42,7 +54,7 @@ struct qtnf_bus {
enum qtnf_fw_state fw_state;
u32 chip;
u32 chiprev;
const struct qtnf_bus_ops *bus_ops;
struct qtnf_bus_ops *bus_ops;
struct qtnf_wmac *mac[QTNF_MAX_MAC];
struct qtnf_qlink_transport trans;
struct qtnf_hw_info hw_info;
@ -54,6 +66,8 @@ struct qtnf_bus {
struct work_struct event_work;
struct mutex bus_lock; /* lock during command/event processing */
struct dentry *dbg_dir;
struct notifier_block netdev_nb;
u8 hw_id[ETH_ALEN];
/* bus private data */
char bus_priv[0] __aligned(sizeof(void *));
};
@ -99,9 +113,10 @@ static inline void qtnf_bus_stop(struct qtnf_bus *bus)
bus->bus_ops->stop(bus);
}
static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb,
unsigned int macid, unsigned int vifid)
{
return bus->bus_ops->data_tx(bus, skb);
return bus->bus_ops->data_tx(bus, skb, macid, vifid);
}
static inline void

View File

@ -238,22 +238,29 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
pr_err("VIF%u.%u: FW reported bad MAC: %pM\n",
mac->macid, vif->vifid, vif->mac_addr);
ret = -EINVAL;
goto err_mac;
goto error_del_vif;
}
ret = qtnf_core_net_attach(mac, vif, name, name_assign_t);
if (ret) {
pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid,
vif->vifid);
goto err_net;
goto error_del_vif;
}
if (mac->bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) {
ret = qtnf_cmd_netdev_changeupper(vif, vif->netdev->ifindex);
if (ret) {
unregister_netdevice(vif->netdev);
vif->netdev = NULL;
goto error_del_vif;
}
}
vif->wdev.netdev = vif->netdev;
return &vif->wdev;
err_net:
vif->netdev = NULL;
err_mac:
error_del_vif:
qtnf_cmd_send_del_intf(vif);
err_cmd:
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;

View File

@ -214,6 +214,20 @@ static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
return true;
}
static void qtnf_cmd_tlv_ie_ext_add(struct sk_buff *cmd_skb, u8 eid_ext,
const void *buf, size_t len)
{
struct qlink_tlv_ext_ie *tlv;
tlv = (struct qlink_tlv_ext_ie *)skb_put(cmd_skb, sizeof(*tlv) + len);
tlv->hdr.type = cpu_to_le16(WLAN_EID_EXTENSION);
tlv->hdr.len = cpu_to_le16(sizeof(*tlv) + len - sizeof(tlv->hdr));
tlv->eid_ext = eid_ext;
if (len && buf)
memcpy(tlv->ie_data, buf, len);
}
int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
const struct cfg80211_ap_settings *s)
{
@ -309,6 +323,10 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
memcpy(tlv->val, s->vht_cap, sizeof(*s->vht_cap));
}
if (s->he_cap)
qtnf_cmd_tlv_ie_ext_add(cmd_skb, WLAN_EID_EXT_HE_CAPABILITY,
s->he_cap, sizeof(*s->he_cap));
if (s->acl) {
size_t acl_size = struct_size(s->acl, mac_addrs,
s->acl->n_acl_entries);
@ -1242,10 +1260,7 @@ qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac,
mac_info = &mac->macinfo;
mac_info->bands_cap = resp_info->bands_cap;
memcpy(&mac_info->dev_mac, &resp_info->dev_mac,
sizeof(mac_info->dev_mac));
ether_addr_copy(mac->macaddr, mac_info->dev_mac);
ether_addr_copy(mac->macaddr, resp_info->dev_mac);
vif = qtnf_mac_get_base_vif(mac);
if (vif)
@ -1295,6 +1310,69 @@ static void qtnf_cmd_resp_band_fill_vhtcap(const u8 *info,
memcpy(&bcap->vht_mcs, &vht_cap->supp_mcs, sizeof(bcap->vht_mcs));
}
static void qtnf_cmd_conv_iftype(struct ieee80211_sband_iftype_data
*iftype_data,
const struct qlink_sband_iftype_data
*qlink_data)
{
iftype_data->types_mask = le16_to_cpu(qlink_data->types_mask);
iftype_data->he_cap.has_he = true;
memcpy(&iftype_data->he_cap.he_cap_elem, &qlink_data->he_cap_elem,
sizeof(qlink_data->he_cap_elem));
memcpy(iftype_data->he_cap.ppe_thres, qlink_data->ppe_thres,
ARRAY_SIZE(qlink_data->ppe_thres));
iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80 =
qlink_data->he_mcs_nss_supp.rx_mcs_80;
iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80 =
qlink_data->he_mcs_nss_supp.tx_mcs_80;
iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_160 =
qlink_data->he_mcs_nss_supp.rx_mcs_160;
iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160 =
qlink_data->he_mcs_nss_supp.tx_mcs_160;
iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80p80 =
qlink_data->he_mcs_nss_supp.rx_mcs_80p80;
iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80p80 =
qlink_data->he_mcs_nss_supp.tx_mcs_80p80;
}
static int qtnf_cmd_band_fill_iftype(const u8 *data,
struct ieee80211_supported_band *band)
{
unsigned int i;
struct ieee80211_sband_iftype_data *iftype_data;
const struct qlink_tlv_iftype_data *tlv =
(const struct qlink_tlv_iftype_data *)data;
size_t payload_len = tlv->n_iftype_data * sizeof(*tlv->iftype_data) +
sizeof(*tlv) -
sizeof(struct qlink_tlv_hdr);
if (tlv->hdr.len != cpu_to_le16(payload_len)) {
pr_err("bad IFTYPE_DATA TLV len %u\n", tlv->hdr.len);
return -EINVAL;
}
kfree(band->iftype_data);
band->iftype_data = NULL;
band->n_iftype_data = tlv->n_iftype_data;
if (band->n_iftype_data == 0)
return 0;
iftype_data = kcalloc(band->n_iftype_data, sizeof(*iftype_data),
GFP_KERNEL);
if (!iftype_data) {
band->n_iftype_data = 0;
return -ENOMEM;
}
band->iftype_data = iftype_data;
for (i = 0; i < band->n_iftype_data; i++)
qtnf_cmd_conv_iftype(iftype_data++, &tlv->iftype_data[i]);
return 0;
}
static int
qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
struct qlink_resp_band_info_get *resp,
@ -1308,6 +1386,7 @@ qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
struct ieee80211_channel *chan;
unsigned int chidx = 0;
u32 qflags;
int ret = -EINVAL;
memset(&band->ht_cap, 0, sizeof(band->ht_cap));
memset(&band->vht_cap, 0, sizeof(band->vht_cap));
@ -1445,6 +1524,12 @@ qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
qtnf_cmd_resp_band_fill_vhtcap(tlv->val,
&band->vht_cap);
break;
case QTN_TLV_ID_IFTYPE_DATA:
ret = qtnf_cmd_band_fill_iftype((const uint8_t *)tlv,
band);
if (ret)
goto error_ret;
break;
default:
pr_warn("unknown TLV type: %#x\n", tlv_type);
break;
@ -1472,7 +1557,7 @@ error_ret:
band->channels = NULL;
band->n_channels = 0;
return -EINVAL;
return ret;
}
static int qtnf_cmd_resp_proc_phy_params(struct qtnf_wmac *mac,
@ -2756,3 +2841,35 @@ out:
qtnf_bus_unlock(bus);
return ret;
}
int qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain)
{
struct qtnf_bus *bus = vif->mac->bus;
struct sk_buff *cmd_skb;
struct qlink_cmd_ndev_changeupper *cmd;
int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_NDEV_EVENT,
sizeof(*cmd));
if (!cmd_skb)
return -ENOMEM;
pr_debug("[VIF%u.%u] set broadcast domain to %d\n",
vif->mac->macid, vif->vifid, br_domain);
cmd = (struct qlink_cmd_ndev_changeupper *)cmd_skb->data;
cmd->nehdr.event = cpu_to_le16(QLINK_NDEV_EVENT_CHANGEUPPER);
cmd->upper_type = QLINK_NDEV_UPPER_TYPE_BRIDGE;
cmd->br_domain = cpu_to_le32(br_domain);
qtnf_bus_lock(bus);
ret = qtnf_cmd_send(bus, cmd_skb);
qtnf_bus_unlock(bus);
if (ret)
pr_err("[VIF%u.%u] failed to set broadcast domain\n",
vif->mac->macid, vif->vifid);
return ret;
}

View File

@ -75,5 +75,6 @@ int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif,
enum nl80211_tx_power_setting type, int mbm);
int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif,
const struct cfg80211_wowlan *wowl);
int qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain);
#endif /* QLINK_COMMANDS_H_ */

View File

@ -12,6 +12,7 @@
#include "cfg80211.h"
#include "event.h"
#include "util.h"
#include "switchdev.h"
#define QTNF_DMP_MAX_LEN 48
#define QTNF_PRIMARY_VIF_IDX 0
@ -22,13 +23,6 @@ MODULE_PARM_DESC(slave_radar, "set 0 to disable radar detection in slave mode");
static struct dentry *qtnf_debugfs_dir;
struct qtnf_frame_meta_info {
u8 magic_s;
u8 ifidx;
u8 macid;
u8 magic_e;
} __packed;
struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid)
{
struct qtnf_wmac *mac = NULL;
@ -121,7 +115,7 @@ qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_OK;
}
return qtnf_bus_data_tx(mac->bus, skb);
return qtnf_bus_data_tx(mac->bus, skb, mac->macid, vif->vifid);
}
/* Netdev handler for getting stats.
@ -211,6 +205,21 @@ static int qtnf_netdev_set_mac_address(struct net_device *ndev, void *addr)
return ret;
}
static int qtnf_netdev_port_parent_id(struct net_device *ndev,
struct netdev_phys_item_id *ppid)
{
const struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
const struct qtnf_bus *bus = vif->mac->bus;
if (!(bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE))
return -EOPNOTSUPP;
ppid->id_len = sizeof(bus->hw_id);
memcpy(&ppid->id, bus->hw_id, ppid->id_len);
return 0;
}
/* Network device ops handlers */
const struct net_device_ops qtnf_netdev_ops = {
.ndo_open = qtnf_netdev_open,
@ -219,6 +228,7 @@ const struct net_device_ops qtnf_netdev_ops = {
.ndo_tx_timeout = qtnf_netdev_tx_timeout,
.ndo_get_stats64 = qtnf_netdev_get_stats64,
.ndo_set_mac_address = qtnf_netdev_set_mac_address,
.ndo_get_port_parent_id = qtnf_netdev_port_parent_id,
};
static int qtnf_mac_init_single_band(struct wiphy *wiphy,
@ -465,10 +475,8 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
dev = alloc_netdev_mqs(sizeof(struct qtnf_vif *), name,
name_assign_type, ether_setup, 1, 1);
if (!dev) {
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
if (!dev)
return -ENOMEM;
}
vif->netdev = dev;
@ -483,6 +491,9 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
dev->tx_queue_len = 100;
dev->ethtool_ops = &qtnf_ethtool_ops;
if (mac->bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE)
dev->needed_tailroom = sizeof(struct qtnf_frame_meta_info);
qdev_vif = netdev_priv(dev);
*((void **)qdev_vif) = vif;
@ -491,7 +502,7 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
ret = register_netdevice(dev);
if (ret) {
free_netdev(dev);
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
vif->netdev = NULL;
}
return ret;
@ -532,6 +543,9 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
if (!wiphy->bands[band])
continue;
kfree(wiphy->bands[band]->iftype_data);
wiphy->bands[band]->n_iftype_data = 0;
kfree(wiphy->bands[band]->channels);
wiphy->bands[band]->n_channels = 0;
@ -571,6 +585,10 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid)
goto error;
}
/* Use MAC address of the first active radio as a unique device ID */
if (is_zero_ether_addr(mac->bus->hw_id))
ether_addr_copy(mac->bus->hw_id, mac->macaddr);
vif = qtnf_mac_get_base_vif(mac);
if (!vif) {
pr_err("MAC%u: primary VIF is not ready\n", macid);
@ -588,19 +606,19 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid)
ret = qtnf_cmd_send_get_phy_params(mac);
if (ret) {
pr_err("MAC%u: failed to get PHY settings\n", macid);
goto error;
goto error_del_vif;
}
ret = qtnf_mac_init_bands(mac);
if (ret) {
pr_err("MAC%u: failed to init bands\n", macid);
goto error;
goto error_del_vif;
}
ret = qtnf_wiphy_register(&bus->hw_info, mac);
if (ret) {
pr_err("MAC%u: wiphy registration failed\n", macid);
goto error;
goto error_del_vif;
}
mac->wiphy_registered = 1;
@ -612,20 +630,75 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid)
if (ret) {
pr_err("MAC%u: failed to attach netdev\n", macid);
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
vif->netdev = NULL;
goto error;
goto error_del_vif;
}
if (bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) {
ret = qtnf_cmd_netdev_changeupper(vif, vif->netdev->ifindex);
if (ret)
goto error;
}
pr_debug("MAC%u initialized\n", macid);
return 0;
error_del_vif:
qtnf_cmd_send_del_intf(vif);
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
error:
qtnf_core_mac_detach(bus, macid);
return ret;
}
bool qtnf_netdev_is_qtn(const struct net_device *ndev)
{
return ndev->netdev_ops == &qtnf_netdev_ops;
}
static int qtnf_core_netdevice_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
const struct netdev_notifier_changeupper_info *info;
struct qtnf_vif *vif;
int br_domain;
int ret = 0;
if (!qtnf_netdev_is_qtn(ndev))
return NOTIFY_DONE;
if (!net_eq(dev_net(ndev), &init_net))
return NOTIFY_OK;
vif = qtnf_netdev_get_priv(ndev);
switch (event) {
case NETDEV_CHANGEUPPER:
info = ptr;
if (!netif_is_bridge_master(info->upper_dev))
break;
pr_debug("[VIF%u.%u] change bridge: %s %s\n",
vif->mac->macid, vif->vifid,
netdev_name(info->upper_dev),
info->linking ? "add" : "del");
if (info->linking)
br_domain = info->upper_dev->ifindex;
else
br_domain = ndev->ifindex;
ret = qtnf_cmd_netdev_changeupper(vif, br_domain);
break;
default:
break;
}
return notifier_from_errno(ret);
}
int qtnf_core_attach(struct qtnf_bus *bus)
{
unsigned int i;
@ -670,6 +743,10 @@ int qtnf_core_attach(struct qtnf_bus *bus)
goto error;
}
if ((bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) &&
bus->bus_ops->data_tx_use_meta_set)
bus->bus_ops->data_tx_use_meta_set(bus, true);
if (bus->hw_info.num_mac > QTNF_MAX_MAC) {
pr_err("no support for number of MACs=%u\n",
bus->hw_info.num_mac);
@ -686,6 +763,15 @@ int qtnf_core_attach(struct qtnf_bus *bus)
}
}
if (bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) {
bus->netdev_nb.notifier_call = qtnf_core_netdevice_event;
ret = register_netdevice_notifier(&bus->netdev_nb);
if (ret) {
pr_err("failed to register netdev notifier: %d\n", ret);
goto error;
}
}
bus->fw_state = QTNF_FW_STATE_RUNNING;
return 0;
@ -699,6 +785,7 @@ void qtnf_core_detach(struct qtnf_bus *bus)
{
unsigned int macid;
unregister_netdevice_notifier(&bus->netdev_nb);
qtnf_bus_data_rx_stop(bus);
for (macid = 0; macid < QTNF_MAX_MAC; macid++)
@ -727,7 +814,8 @@ EXPORT_SYMBOL_GPL(qtnf_core_detach);
static inline int qtnf_is_frame_meta_magic_valid(struct qtnf_frame_meta_info *m)
{
return m->magic_s == 0xAB && m->magic_e == 0xBA;
return m->magic_s == HBM_FRAME_META_MAGIC_PATTERN_S &&
m->magic_e == HBM_FRAME_META_MAGIC_PATTERN_E;
}
struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb)
@ -782,6 +870,8 @@ struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb)
}
__skb_trim(skb, skb->len - sizeof(*meta));
/* Firmware always handles packets that require flooding */
qtnfmac_switch_mark_skb_flooded(skb);
out:
return ndev;

View File

@ -74,7 +74,6 @@ struct qtnf_vif {
struct qtnf_mac_info {
u8 bands_cap;
u8 dev_mac[ETH_ALEN];
u8 num_tx_chain;
u8 num_rx_chain;
u16 max_ap_assoc_sta;
@ -153,6 +152,7 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev);
void qtnf_netdev_updown(struct net_device *ndev, bool up);
void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted);
struct dentry *qtnf_get_debugfs_dir(void);
bool qtnf_netdev_is_qtn(const struct net_device *ndev);
static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev)
{

View File

@ -532,7 +532,7 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *ps)
return 1;
}
static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
static int qtnf_pcie_skb_send(struct qtnf_bus *bus, struct sk_buff *skb)
{
struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
struct qtnf_pcie_bus_priv *priv = &ps->base;
@ -608,6 +608,38 @@ tx_done:
return NETDEV_TX_OK;
}
static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb,
unsigned int macid, unsigned int vifid)
{
return qtnf_pcie_skb_send(bus, skb);
}
static int qtnf_pcie_data_tx_meta(struct qtnf_bus *bus, struct sk_buff *skb,
unsigned int macid, unsigned int vifid)
{
struct qtnf_frame_meta_info *meta;
int tail_need = sizeof(*meta) - skb_tailroom(skb);
int ret;
if (tail_need > 0 && pskb_expand_head(skb, 0, tail_need, GFP_ATOMIC)) {
skb->dev->stats.tx_dropped++;
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
meta = skb_put(skb, sizeof(*meta));
meta->magic_s = HBM_FRAME_META_MAGIC_PATTERN_S;
meta->magic_e = HBM_FRAME_META_MAGIC_PATTERN_E;
meta->macid = macid;
meta->ifidx = vifid;
ret = qtnf_pcie_skb_send(bus, skb);
if (unlikely(ret == NETDEV_TX_BUSY))
__skb_trim(skb, skb->len - sizeof(*meta));
return ret;
}
static irqreturn_t qtnf_pcie_pearl_interrupt(int irq, void *data)
{
struct qtnf_bus *bus = (struct qtnf_bus *)data;
@ -796,13 +828,22 @@ static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus)
qtnf_disable_hdp_irqs(ps);
}
static const struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = {
static void qtnf_pearl_tx_use_meta_info_set(struct qtnf_bus *bus, bool use_meta)
{
if (use_meta)
bus->bus_ops->data_tx = qtnf_pcie_data_tx_meta;
else
bus->bus_ops->data_tx = qtnf_pcie_data_tx;
}
static struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = {
/* control path methods */
.control_tx = qtnf_pcie_control_tx,
/* data path methods */
.data_tx = qtnf_pcie_data_tx,
.data_tx_timeout = qtnf_pcie_data_tx_timeout,
.data_tx_use_meta_set = qtnf_pearl_tx_use_meta_info_set,
.data_rx_start = qtnf_pcie_data_rx_start,
.data_rx_stop = qtnf_pcie_data_rx_stop,
};
@ -905,7 +946,7 @@ static int qtnf_ep_fw_send(struct pci_dev *pdev, uint32_t size,
memcpy(pdata, pblk, len);
hdr->crc = cpu_to_le32(~crc32(0, pdata, len));
ret = qtnf_pcie_data_tx(bus, skb);
ret = qtnf_pcie_skb_send(bus, skb);
return (ret == NETDEV_TX_OK) ? len : 0;
}

View File

@ -497,7 +497,8 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_topaz_state *ts)
return 1;
}
static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb,
unsigned int macid, unsigned int vifid)
{
struct qtnf_pcie_topaz_state *ts = (void *)get_bus_priv(bus);
struct qtnf_pcie_bus_priv *priv = &ts->base;
@ -740,7 +741,7 @@ static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus)
napi_disable(&bus->mux_napi);
}
static const struct qtnf_bus_ops qtnf_pcie_topaz_bus_ops = {
static struct qtnf_bus_ops qtnf_pcie_topaz_bus_ops = {
/* control path methods */
.control_tx = qtnf_pcie_control_tx,

View File

@ -59,6 +59,7 @@ struct qlink_msg_header {
* @QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR: device supports MAC Address
* Randomization in probe requests.
* @QLINK_HW_CAPAB_OBSS_SCAN: device can perform OBSS scanning.
* @QLINK_HW_CAPAB_HW_BRIDGE: device has hardware switch capabilities.
*/
enum qlink_hw_capab {
QLINK_HW_CAPAB_REG_UPDATE = BIT(0),
@ -69,6 +70,7 @@ enum qlink_hw_capab {
QLINK_HW_CAPAB_OBSS_SCAN = BIT(5),
QLINK_HW_CAPAB_SCAN_DWELL = BIT(6),
QLINK_HW_CAPAB_SAE = BIT(8),
QLINK_HW_CAPAB_HW_BRIDGE = BIT(9),
};
enum qlink_iface_type {
@ -219,6 +221,8 @@ struct qlink_sta_info_state {
* @QLINK_CMD_START_CAC: start radar detection procedure on a specified channel.
* @QLINK_CMD_TXPWR: get or set current channel transmit power for
* the specified MAC.
* @QLINK_CMD_NDEV_EVENT: signalizes changes made with a corresponding network
* device.
*/
enum qlink_cmd_type {
QLINK_CMD_FW_INIT = 0x0001,
@ -251,6 +255,7 @@ enum qlink_cmd_type {
QLINK_CMD_DEL_STA = 0x0052,
QLINK_CMD_SCAN = 0x0053,
QLINK_CMD_CHAN_STATS = 0x0054,
QLINK_CMD_NDEV_EVENT = 0x0055,
QLINK_CMD_CONNECT = 0x0060,
QLINK_CMD_DISCONNECT = 0x0061,
QLINK_CMD_PM_SET = 0x0062,
@ -771,6 +776,42 @@ struct qlink_cmd_wowlan_set {
u8 data[0];
} __packed;
enum qlink_ndev_event_type {
QLINK_NDEV_EVENT_CHANGEUPPER,
};
/**
* struct qlink_cmd_ndev_event - data for QLINK_CMD_NDEV_EVENT command
*
* @event: type of event, one of &enum qlink_ndev_event_type
*/
struct qlink_cmd_ndev_event {
struct qlink_cmd chdr;
__le16 event;
u8 rsvd[2];
} __packed;
enum qlink_ndev_upper_type {
QLINK_NDEV_UPPER_TYPE_NONE,
QLINK_NDEV_UPPER_TYPE_BRIDGE,
};
/**
* struct qlink_cmd_ndev_changeupper - data for QLINK_NDEV_EVENT_CHANGEUPPER
*
* @br_domain: layer 2 broadcast domain ID that ndev is a member of
* @upper_type: type of upper device, one of &enum qlink_ndev_upper_type
*/
struct qlink_cmd_ndev_changeupper {
struct qlink_cmd_ndev_event nehdr;
__le64 flags;
__le32 br_domain;
__le32 netspace_id;
__le16 vlanid;
u8 upper_type;
u8 rsvd[1];
} __packed;
/* QLINK Command Responses messages related definitions
*/
@ -1228,6 +1269,7 @@ struct qlink_event_mic_failure {
* @QTN_TLV_ID_SCAN_SAMPLE_DURATION: total duration of sampling a single channel
* during a scan including off-channel dwell time and operating channel
* time.
* @QTN_TLV_ID_IFTYPE_DATA: supported band data.
*/
enum qlink_tlv_id {
QTN_TLV_ID_FRAG_THRESH = 0x0201,
@ -1263,6 +1305,7 @@ enum qlink_tlv_id {
QTN_TLV_ID_SCAN_DWELL_ACTIVE = 0x0413,
QTN_TLV_ID_SCAN_DWELL_PASSIVE = 0x0416,
QTN_TLV_ID_SCAN_SAMPLE_DURATION = 0x0417,
QTN_TLV_ID_IFTYPE_DATA = 0x0418,
};
struct qlink_tlv_hdr {
@ -1424,6 +1467,39 @@ struct qlink_tlv_ie_set {
u8 ie_data[0];
} __packed;
/**
* struct qlink_tlv_ext_ie - extension IE
*
* @eid_ext: element ID extension, one of &enum ieee80211_eid_ext.
* @ie_data: IEs data.
*/
struct qlink_tlv_ext_ie {
struct qlink_tlv_hdr hdr;
u8 eid_ext;
u8 ie_data[0];
} __packed;
#define IEEE80211_HE_PPE_THRES_MAX_LEN 25
struct qlink_sband_iftype_data {
__le16 types_mask;
struct ieee80211_he_cap_elem he_cap_elem;
struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp;
u8 ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN];
} __packed;
/**
* struct qlink_tlv_iftype_data - data for QTN_TLV_ID_IFTYPE_DATA
*
* @n_iftype_data: number of entries in iftype_data.
* @iftype_data: interface type data entries.
*/
struct qlink_tlv_iftype_data {
struct qlink_tlv_hdr hdr;
u8 n_iftype_data;
u8 rsvd[3];
struct qlink_sband_iftype_data iftype_data[0];
} __packed;
struct qlink_chan_stats {
__le32 chan_num;
__le32 cca_tx;

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2019 Quantenna Communications. All rights reserved. */
#ifndef QTNFMAC_SWITCHDEV_H_
#define QTNFMAC_SWITCHDEV_H_
#include <linux/skbuff.h>
#ifdef CONFIG_NET_SWITCHDEV
static inline void qtnfmac_switch_mark_skb_flooded(struct sk_buff *skb)
{
skb->offload_fwd_mark = 1;
}
#else
static inline void qtnfmac_switch_mark_skb_flooded(struct sk_buff *skb)
{
}
#endif
#endif /* QTNFMAC_SWITCHDEV_H_ */

View File

@ -5393,18 +5393,13 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work)
{
struct rtl8xxxu_priv *priv;
struct rtl8723bu_c2h *c2h;
struct ieee80211_vif *vif;
struct device *dev;
struct sk_buff *skb = NULL;
unsigned long flags;
int len;
u8 bt_info = 0;
struct rtl8xxxu_btcoex *btcoex;
priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work);
vif = priv->vif;
btcoex = &priv->bt_coex;
dev = &priv->udev->dev;
if (priv->rf_paths > 1)
goto out;
@ -5415,7 +5410,6 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work)
spin_unlock_irqrestore(&priv->c2hcmd_lock, flags);
c2h = (struct rtl8723bu_c2h *)skb->data;
len = skb->len - 2;
switch (c2h->id) {
case C2H_8723B_BT_INFO:

View File

@ -85,20 +85,19 @@ u32 rtl88e_phy_query_rf_reg(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, readback_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
regaddr, rfpath, bitmask);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
original_value = _rtl88e_phy_rf_serial_read(hw, rfpath, regaddr);
bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
@ -112,13 +111,12 @@ void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
regaddr, bitmask, data, rfpath);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
if (bitmask != RFREG_OFFSET_MASK) {
original_value = _rtl88e_phy_rf_serial_read(hw,
@ -133,7 +131,7 @@ void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw,
_rtl88e_phy_rf_serial_write(hw, rfpath, regaddr, data);
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
@ -166,9 +164,9 @@ static u32 _rtl88e_phy_rf_serial_read(struct ieee80211_hw *hw,
(newoffset << 23) | BLSSIREADEDGE;
rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
tmplong & (~BLSSIREADEDGE));
mdelay(1);
udelay(10);
rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
mdelay(2);
udelay(120);
if (rfpath == RF90_PATH_A)
rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
BIT(8));

View File

@ -307,16 +307,15 @@ u32 rtl92d_phy_query_rf_reg(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, readback_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
regaddr, rfpath, bitmask);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
original_value = _rtl92d_phy_rf_serial_read(hw, rfpath, regaddr);
bitshift = _rtl92d_phy_calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
regaddr, rfpath, bitmask, original_value);
@ -329,14 +328,13 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
u32 original_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
regaddr, bitmask, data, rfpath);
if (bitmask == 0)
return;
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
if (rtlphy->rf_mode != RF_OP_BY_FW) {
if (bitmask != RFREG_OFFSET_MASK) {
original_value = _rtl92d_phy_rf_serial_read(hw,
@ -347,7 +345,7 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
}
_rtl92d_phy_rf_serial_write(hw, rfpath, regaddr, data);
}
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
regaddr, bitmask, data, rfpath);

View File

@ -84,19 +84,18 @@ u32 rtl92ee_phy_query_rf_reg(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, readback_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
regaddr, rfpath, bitmask);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
original_value = _rtl92ee_phy_rf_serial_read(hw , rfpath, regaddr);
bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x),rfpath(%#x),bitmask(%#x),original_value(%#x)\n",
@ -111,13 +110,12 @@ void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
addr, bitmask, data, rfpath);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
if (bitmask != RFREG_OFFSET_MASK) {
original_value = _rtl92ee_phy_rf_serial_read(hw, rfpath, addr);
@ -127,7 +125,7 @@ void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw,
_rtl92ee_phy_rf_serial_write(hw, rfpath, addr, data);
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
@ -160,9 +158,8 @@ static u32 _rtl92ee_phy_rf_serial_read(struct ieee80211_hw *hw,
(newoffset << 23) | BLSSIREADEDGE;
rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
tmplong & (~BLSSIREADEDGE));
mdelay(1);
rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
mdelay(2);
udelay(20);
if (rfpath == RF90_PATH_A)
rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
BIT(8));

View File

@ -37,13 +37,12 @@ u32 rtl8723e_phy_query_rf_reg(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value = 0, readback_value, bitshift;
struct rtl_phy *rtlphy = &rtlpriv->phy;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
regaddr, rfpath, bitmask);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
if (rtlphy->rf_mode != RF_OP_BY_FW) {
original_value = rtl8723_phy_rf_serial_read(hw,
@ -53,7 +52,7 @@ u32 rtl8723e_phy_query_rf_reg(struct ieee80211_hw *hw,
bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
@ -69,13 +68,12 @@ void rtl8723e_phy_set_rf_reg(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &rtlpriv->phy;
u32 original_value = 0, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
regaddr, bitmask, data, rfpath);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
if (rtlphy->rf_mode != RF_OP_BY_FW) {
if (bitmask != RFREG_OFFSET_MASK) {
@ -99,7 +97,7 @@ void rtl8723e_phy_set_rf_reg(struct ieee80211_hw *hw,
_rtl8723e_phy_fw_rf_serial_write(hw, rfpath, regaddr, data);
}
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",

View File

@ -33,19 +33,18 @@ u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, readback_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
regaddr, rfpath, bitmask);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr);
bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
@ -59,13 +58,12 @@ void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path path,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
regaddr, bitmask, data, path);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
if (bitmask != RFREG_OFFSET_MASK) {
original_value = rtl8723_phy_rf_serial_read(hw, path,
@ -77,7 +75,7 @@ void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path path,
rtl8723_phy_rf_serial_write(hw, path, regaddr, data);
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",

View File

@ -89,12 +89,10 @@ u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw,
(newoffset << 23) | BLSSIREADEDGE;
rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
tmplong & (~BLSSIREADEDGE));
mdelay(1);
rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
mdelay(1);
rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
tmplong | BLSSIREADEDGE);
mdelay(1);
udelay(120);
if (rfpath == RF90_PATH_A)
rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
BIT(8));

View File

@ -139,19 +139,18 @@ u32 rtl8821ae_phy_query_rf_reg(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, readback_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
regaddr, rfpath, bitmask);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
original_value = _rtl8821ae_phy_rf_serial_read(hw, rfpath, regaddr);
bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
@ -166,13 +165,12 @@ void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, bitshift;
unsigned long flags;
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
regaddr, bitmask, data, rfpath);
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
spin_lock(&rtlpriv->locks.rf_lock);
if (bitmask != RFREG_OFFSET_MASK) {
original_value =
@ -183,7 +181,7 @@ void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw,
_rtl8821ae_phy_rf_serial_write(hw, rfpath, regaddr, data);
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
spin_unlock(&rtlpriv->locks.rf_lock);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",

View File

@ -14,6 +14,7 @@ struct rtw_hci_ops {
int (*start)(struct rtw_dev *rtwdev);
void (*stop)(struct rtw_dev *rtwdev);
void (*deep_ps)(struct rtw_dev *rtwdev, bool enter);
void (*link_ps)(struct rtw_dev *rtwdev, bool enter);
int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
@ -53,6 +54,11 @@ static inline void rtw_hci_deep_ps(struct rtw_dev *rtwdev, bool enter)
rtwdev->hci.ops->deep_ps(rtwdev, enter);
}
static inline void rtw_hci_link_ps(struct rtw_dev *rtwdev, bool enter)
{
rtwdev->hci.ops->link_ps(rtwdev, enter);
}
static inline int
rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
{

View File

@ -1060,23 +1060,49 @@ static void rtw_pci_io_unmapping(struct rtw_dev *rtwdev,
static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data)
{
u16 write_addr;
u16 remainder = addr & 0x3;
u16 remainder = addr & ~(BITS_DBI_WREN | BITS_DBI_ADDR_MASK);
u8 flag;
u8 cnt = 20;
u8 cnt;
write_addr = ((addr & 0x0ffc) | (BIT(0) << (remainder + 12)));
write_addr = addr & BITS_DBI_ADDR_MASK;
write_addr |= u16_encode_bits(BIT(remainder), BITS_DBI_WREN);
rtw_write8(rtwdev, REG_DBI_WDATA_V1 + remainder, data);
rtw_write16(rtwdev, REG_DBI_FLAG_V1, write_addr);
rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, 0x01);
rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_WFLAG >> 16);
flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
while (flag && (cnt != 0)) {
udelay(10);
for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
cnt--;
if (flag == 0)
return;
udelay(10);
}
WARN(flag, "DBI write fail\n");
WARN(flag, "failed to write to DBI register, addr=0x%04x\n", addr);
}
static int rtw_dbi_read8(struct rtw_dev *rtwdev, u16 addr, u8 *value)
{
u16 read_addr = addr & BITS_DBI_ADDR_MASK;
u8 flag;
u8 cnt;
rtw_write16(rtwdev, REG_DBI_FLAG_V1, read_addr);
rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_RFLAG >> 16);
for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
if (flag == 0) {
read_addr = REG_DBI_RDATA_V1 + (addr & 3);
*value = rtw_read8(rtwdev, read_addr);
return 0;
}
udelay(10);
}
WARN(1, "failed to read DBI register, addr=0x%04x\n", addr);
return -EIO;
}
static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
@ -1087,23 +1113,113 @@ static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
rtw_write16(rtwdev, REG_MDIO_V1, data);
page = addr < 0x20 ? 0 : 1;
page += g1 ? 0 : 2;
rtw_write8(rtwdev, REG_PCIE_MIX_CFG, addr & 0x1f);
page = addr < RTW_PCI_MDIO_PG_SZ ? 0 : 1;
page += g1 ? RTW_PCI_MDIO_PG_OFFS_G1 : RTW_PCI_MDIO_PG_OFFS_G2;
rtw_write8(rtwdev, REG_PCIE_MIX_CFG, addr & BITS_MDIO_ADDR_MASK);
rtw_write8(rtwdev, REG_PCIE_MIX_CFG + 3, page);
rtw_write32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1, 1);
wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1);
cnt = 20;
while (wflag && (cnt != 0)) {
udelay(10);
for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG,
BIT_MDIO_WFLAG_V1);
cnt--;
if (wflag == 0)
return;
udelay(10);
}
WARN(wflag, "MDIO write fail\n");
WARN(wflag, "failed to write to MDIO register, addr=0x%02x\n", addr);
}
static void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable)
{
u8 value;
int ret;
ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
if (ret) {
rtw_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret);
return;
}
if (enable)
value |= BIT_CLKREQ_SW_EN;
else
value &= ~BIT_CLKREQ_SW_EN;
rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
}
static void rtw_pci_aspm_set(struct rtw_dev *rtwdev, bool enable)
{
u8 value;
int ret;
ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
if (ret) {
rtw_err(rtwdev, "failed to read ASPM, ret=%d", ret);
return;
}
if (enable)
value |= BIT_L1_SW_EN;
else
value &= ~BIT_L1_SW_EN;
rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
}
static void rtw_pci_link_ps(struct rtw_dev *rtwdev, bool enter)
{
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
/* Like CLKREQ, ASPM is also implemented by two HW modules, and can
* only be enabled when host supports it.
*
* And ASPM mechanism should be enabled when driver/firmware enters
* power save mode, without having heavy traffic. Because we've
* experienced some inter-operability issues that the link tends
* to enter L1 state on the fly even when driver is having high
* throughput. This is probably because the ASPM behavior slightly
* varies from different SOC.
*/
if (rtwpci->link_ctrl & PCI_EXP_LNKCTL_ASPM_L1)
rtw_pci_aspm_set(rtwdev, enter);
}
static void rtw_pci_link_cfg(struct rtw_dev *rtwdev)
{
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct pci_dev *pdev = rtwpci->pdev;
u16 link_ctrl;
int ret;
/* Though there is standard PCIE configuration space to set the
* link control register, but by Realtek's design, driver should
* check if host supports CLKREQ/ASPM to enable the HW module.
*
* These functions are implemented by two HW modules associated,
* one is responsible to access PCIE configuration space to
* follow the host settings, and another is in charge of doing
* CLKREQ/ASPM mechanisms, it is default disabled. Because sometimes
* the host does not support it, and due to some reasons or wrong
* settings (ex. CLKREQ# not Bi-Direction), it could lead to device
* loss if HW misbehaves on the link.
*
* Hence it's designed that driver should first check the PCIE
* configuration space is sync'ed and enabled, then driver can turn
* on the other module that is actually working on the mechanism.
*/
ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctrl);
if (ret) {
rtw_err(rtwdev, "failed to read PCI cap, ret=%d\n", ret);
return;
}
if (link_ctrl & PCI_EXP_LNKCTL_CLKREQ_EN)
rtw_pci_clkreq_set(rtwdev, true);
rtwpci->link_ctrl = link_ctrl;
}
static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
@ -1144,6 +1260,8 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
else
rtw_dbi_write8(rtwdev, offset, value);
}
rtw_pci_link_cfg(rtwdev);
}
static int rtw_pci_claim(struct rtw_dev *rtwdev, struct pci_dev *pdev)
@ -1211,6 +1329,7 @@ static struct rtw_hci_ops rtw_pci_ops = {
.start = rtw_pci_start,
.stop = rtw_pci_stop,
.deep_ps = rtw_pci_deep_ps,
.link_ps = rtw_pci_link_ps,
.read8 = rtw_pci_read8,
.read16 = rtw_pci_read16,

View File

@ -20,10 +20,25 @@
#define BIT_RST_TRXDMA_INTF BIT(20)
#define BIT_RX_TAG_EN BIT(15)
#define REG_DBI_WDATA_V1 0x03E8
#define REG_DBI_RDATA_V1 0x03EC
#define REG_DBI_FLAG_V1 0x03F0
#define BIT_DBI_RFLAG BIT(17)
#define BIT_DBI_WFLAG BIT(16)
#define BITS_DBI_WREN GENMASK(15, 12)
#define BITS_DBI_ADDR_MASK GENMASK(11, 2)
#define REG_MDIO_V1 0x03F4
#define REG_PCIE_MIX_CFG 0x03F8
#define BITS_MDIO_ADDR_MASK GENMASK(4, 0)
#define BIT_MDIO_WFLAG_V1 BIT(5)
#define RTW_PCI_MDIO_PG_SZ BIT(5)
#define RTW_PCI_MDIO_PG_OFFS_G1 0
#define RTW_PCI_MDIO_PG_OFFS_G2 2
#define RTW_PCI_WR_RETRY_CNT 20
#define RTK_PCIE_LINK_CFG 0x0719
#define BIT_CLKREQ_SW_EN BIT(4)
#define BIT_L1_SW_EN BIT(3)
#define BIT_PCI_BCNQ_FLAG BIT(4)
#define RTK_PCI_TXBD_DESA_BCNQ 0x308
@ -190,6 +205,7 @@ struct rtw_pci {
u16 rx_tag;
struct rtw_pci_tx_ring tx_rings[RTK_MAX_TX_QUEUE_NUM];
struct rtw_pci_rx_ring rx_rings[RTK_MAX_RX_QUEUE_NUM];
u16 link_ctrl;
void __iomem *mmap;
};

View File

@ -31,6 +31,7 @@ int rtw_enter_ips(struct rtw_dev *rtwdev)
rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
rtw_core_stop(rtwdev);
rtw_hci_link_ps(rtwdev, true);
return 0;
}
@ -49,6 +50,8 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
{
int ret;
rtw_hci_link_ps(rtwdev, false);
ret = rtw_ips_pwr_up(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to leave ips state\n");
@ -150,6 +153,7 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
conf->rlbm = 0;
conf->smart_ps = 0;
rtw_hci_link_ps(rtwdev, false);
rtw_fw_set_pwr_mode(rtwdev);
rtw_fw_leave_lps_state_check(rtwdev);
@ -187,6 +191,8 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
rtw_fw_set_pwr_mode(rtwdev);
rtw_hci_link_ps(rtwdev, true);
set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
}