2019-01-14 17:39:45 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
/* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */
|
2017-05-12 05:51:01 +08:00
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/if_ether.h>
|
2020-01-27 18:46:58 +08:00
|
|
|
#include <linux/nospec.h>
|
2017-05-12 05:51:01 +08:00
|
|
|
|
|
|
|
#include "core.h"
|
|
|
|
#include "bus.h"
|
|
|
|
#include "trans.h"
|
|
|
|
#include "commands.h"
|
|
|
|
#include "cfg80211.h"
|
|
|
|
#include "event.h"
|
|
|
|
#include "util.h"
|
2019-11-18 16:23:12 +08:00
|
|
|
#include "switchdev.h"
|
2017-05-12 05:51:01 +08:00
|
|
|
|
|
|
|
#define QTNF_DMP_MAX_LEN 48
|
|
|
|
#define QTNF_PRIMARY_VIF_IDX 0
|
|
|
|
|
2019-04-09 15:35:10 +08:00
|
|
|
static bool slave_radar = true;
|
|
|
|
module_param(slave_radar, bool, 0644);
|
|
|
|
MODULE_PARM_DESC(slave_radar, "set 0 to disable radar detection in slave mode");
|
|
|
|
|
2020-01-09 21:17:52 +08:00
|
|
|
static bool dfs_offload;
|
|
|
|
module_param(dfs_offload, bool, 0644);
|
|
|
|
MODULE_PARM_DESC(dfs_offload, "set 1 to enable DFS offload to firmware");
|
|
|
|
|
2019-04-09 15:35:12 +08:00
|
|
|
static struct dentry *qtnf_debugfs_dir;
|
|
|
|
|
2020-01-09 21:17:51 +08:00
|
|
|
bool qtnf_slave_radar_get(void)
|
|
|
|
{
|
|
|
|
return slave_radar;
|
|
|
|
}
|
|
|
|
|
2020-01-09 21:17:52 +08:00
|
|
|
bool qtnf_dfs_offload_get(void)
|
|
|
|
{
|
|
|
|
return dfs_offload;
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid)
|
|
|
|
{
|
|
|
|
struct qtnf_wmac *mac = NULL;
|
|
|
|
|
2020-01-27 18:46:58 +08:00
|
|
|
if (macid >= QTNF_MAX_MAC) {
|
2017-05-12 05:51:01 +08:00
|
|
|
pr_err("invalid MAC index %u\n", macid);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-01-27 18:46:58 +08:00
|
|
|
macid = array_index_nospec(macid, QTNF_MAX_MAC);
|
2017-05-12 05:51:01 +08:00
|
|
|
mac = bus->mac[macid];
|
|
|
|
|
|
|
|
if (unlikely(!mac)) {
|
|
|
|
pr_err("MAC%u: not initialized\n", macid);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mac;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Netdev handler for open.
|
|
|
|
*/
|
|
|
|
static int qtnf_netdev_open(struct net_device *ndev)
|
|
|
|
{
|
|
|
|
netif_carrier_off(ndev);
|
|
|
|
qtnf_netdev_updown(ndev, 1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Netdev handler for close.
|
|
|
|
*/
|
|
|
|
static int qtnf_netdev_close(struct net_device *ndev)
|
|
|
|
{
|
|
|
|
netif_carrier_off(ndev);
|
|
|
|
qtnf_virtual_intf_cleanup(ndev);
|
|
|
|
qtnf_netdev_updown(ndev, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-13 19:06:55 +08:00
|
|
|
static void qtnf_packet_send_hi_pri(struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(skb->dev);
|
|
|
|
|
|
|
|
skb_queue_tail(&vif->high_pri_tx_queue, skb);
|
|
|
|
queue_work(vif->mac->bus->hprio_workqueue, &vif->high_pri_tx_work);
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
/* Netdev handler for data transmission.
|
|
|
|
*/
|
2018-04-24 21:18:04 +08:00
|
|
|
static netdev_tx_t
|
2017-05-12 05:51:01 +08:00
|
|
|
qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif;
|
|
|
|
struct qtnf_wmac *mac;
|
|
|
|
|
|
|
|
vif = qtnf_netdev_get_priv(ndev);
|
|
|
|
|
|
|
|
if (unlikely(skb->dev != ndev)) {
|
|
|
|
pr_err_ratelimited("invalid skb->dev");
|
|
|
|
dev_kfree_skb_any(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)) {
|
|
|
|
pr_err_ratelimited("%s: VIF not initialized\n", ndev->name);
|
|
|
|
dev_kfree_skb_any(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
mac = vif->mac;
|
|
|
|
if (unlikely(!mac)) {
|
|
|
|
pr_err_ratelimited("%s: NULL mac pointer", ndev->name);
|
|
|
|
dev_kfree_skb_any(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
|
|
|
|
pr_err_ratelimited("%s: invalid skb len %d\n", ndev->name,
|
|
|
|
skb->len);
|
|
|
|
dev_kfree_skb_any(skb);
|
|
|
|
ndev->stats.tx_dropped++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tx path is enabled: reset vif timeout */
|
|
|
|
vif->cons_tx_timeout_cnt = 0;
|
|
|
|
|
2019-11-13 19:06:55 +08:00
|
|
|
if (unlikely(skb->protocol == htons(ETH_P_PAE))) {
|
|
|
|
qtnf_packet_send_hi_pri(skb);
|
|
|
|
qtnf_update_tx_stats(ndev, skb);
|
|
|
|
return NETDEV_TX_OK;
|
|
|
|
}
|
|
|
|
|
2019-11-18 16:23:08 +08:00
|
|
|
return qtnf_bus_data_tx(mac->bus, skb, mac->macid, vif->vifid);
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Netdev handler for getting stats.
|
|
|
|
*/
|
2018-01-22 20:46:26 +08:00
|
|
|
static void qtnf_netdev_get_stats64(struct net_device *ndev,
|
|
|
|
struct rtnl_link_stats64 *stats)
|
2017-05-12 05:51:01 +08:00
|
|
|
{
|
2018-01-22 20:46:26 +08:00
|
|
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
|
|
|
unsigned int start;
|
|
|
|
int cpu;
|
|
|
|
|
|
|
|
netdev_stats_to_stats64(stats, &ndev->stats);
|
|
|
|
|
|
|
|
if (!vif->stats64)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
|
|
struct pcpu_sw_netstats *stats64;
|
|
|
|
u64 rx_packets, rx_bytes;
|
|
|
|
u64 tx_packets, tx_bytes;
|
|
|
|
|
|
|
|
stats64 = per_cpu_ptr(vif->stats64, cpu);
|
|
|
|
|
|
|
|
do {
|
|
|
|
start = u64_stats_fetch_begin_irq(&stats64->syncp);
|
|
|
|
rx_packets = stats64->rx_packets;
|
|
|
|
rx_bytes = stats64->rx_bytes;
|
|
|
|
tx_packets = stats64->tx_packets;
|
|
|
|
tx_bytes = stats64->tx_bytes;
|
|
|
|
} while (u64_stats_fetch_retry_irq(&stats64->syncp, start));
|
|
|
|
|
|
|
|
stats->rx_packets += rx_packets;
|
|
|
|
stats->rx_bytes += rx_bytes;
|
|
|
|
stats->tx_packets += tx_packets;
|
|
|
|
stats->tx_bytes += tx_bytes;
|
|
|
|
}
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Netdev handler for transmission timeout.
|
|
|
|
*/
|
netdev: pass the stuck queue to the timeout handler
This allows incrementing the correct timeout statistic without any mess.
Down the road, devices can learn to reset just the specific queue.
The patch was generated with the following script:
use strict;
use warnings;
our $^I = '.bak';
my @work = (
["arch/m68k/emu/nfeth.c", "nfeth_tx_timeout"],
["arch/um/drivers/net_kern.c", "uml_net_tx_timeout"],
["arch/um/drivers/vector_kern.c", "vector_net_tx_timeout"],
["arch/xtensa/platforms/iss/network.c", "iss_net_tx_timeout"],
["drivers/char/pcmcia/synclink_cs.c", "hdlcdev_tx_timeout"],
["drivers/infiniband/ulp/ipoib/ipoib_main.c", "ipoib_timeout"],
["drivers/infiniband/ulp/ipoib/ipoib_main.c", "ipoib_timeout"],
["drivers/message/fusion/mptlan.c", "mpt_lan_tx_timeout"],
["drivers/misc/sgi-xp/xpnet.c", "xpnet_dev_tx_timeout"],
["drivers/net/appletalk/cops.c", "cops_timeout"],
["drivers/net/arcnet/arcdevice.h", "arcnet_timeout"],
["drivers/net/arcnet/arcnet.c", "arcnet_timeout"],
["drivers/net/arcnet/com20020.c", "arcnet_timeout"],
["drivers/net/ethernet/3com/3c509.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c515.c", "corkscrew_timeout"],
["drivers/net/ethernet/3com/3c574_cs.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c589_cs.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c59x.c", "vortex_tx_timeout"],
["drivers/net/ethernet/3com/3c59x.c", "vortex_tx_timeout"],
["drivers/net/ethernet/3com/typhoon.c", "typhoon_tx_timeout"],
["drivers/net/ethernet/8390/8390.h", "ei_tx_timeout"],
["drivers/net/ethernet/8390/8390.h", "eip_tx_timeout"],
["drivers/net/ethernet/8390/8390.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/8390p.c", "eip_tx_timeout"],
["drivers/net/ethernet/8390/ax88796.c", "ax_ei_tx_timeout"],
["drivers/net/ethernet/8390/axnet_cs.c", "axnet_tx_timeout"],
["drivers/net/ethernet/8390/etherh.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/hydra.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/mac8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/mcf8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/lib8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/ne2k-pci.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/pcnet_cs.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/smc-ultra.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/wd.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/zorro8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/adaptec/starfire.c", "tx_timeout"],
["drivers/net/ethernet/agere/et131x.c", "et131x_tx_timeout"],
["drivers/net/ethernet/allwinner/sun4i-emac.c", "emac_timeout"],
["drivers/net/ethernet/alteon/acenic.c", "ace_watchdog"],
["drivers/net/ethernet/amazon/ena/ena_netdev.c", "ena_tx_timeout"],
["drivers/net/ethernet/amd/7990.h", "lance_tx_timeout"],
["drivers/net/ethernet/amd/7990.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/a2065.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/am79c961a.c", "am79c961_timeout"],
["drivers/net/ethernet/amd/amd8111e.c", "amd8111e_tx_timeout"],
["drivers/net/ethernet/amd/ariadne.c", "ariadne_tx_timeout"],
["drivers/net/ethernet/amd/atarilance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/au1000_eth.c", "au1000_tx_timeout"],
["drivers/net/ethernet/amd/declance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/lance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/mvme147.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/ni65.c", "ni65_timeout"],
["drivers/net/ethernet/amd/nmclan_cs.c", "mace_tx_timeout"],
["drivers/net/ethernet/amd/pcnet32.c", "pcnet32_tx_timeout"],
["drivers/net/ethernet/amd/sunlance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/xgbe/xgbe-drv.c", "xgbe_tx_timeout"],
["drivers/net/ethernet/apm/xgene-v2/main.c", "xge_timeout"],
["drivers/net/ethernet/apm/xgene/xgene_enet_main.c", "xgene_enet_timeout"],
["drivers/net/ethernet/apple/macmace.c", "mace_tx_timeout"],
["drivers/net/ethernet/atheros/ag71xx.c", "ag71xx_tx_timeout"],
["drivers/net/ethernet/atheros/alx/main.c", "alx_tx_timeout"],
["drivers/net/ethernet/atheros/atl1c/atl1c_main.c", "atl1c_tx_timeout"],
["drivers/net/ethernet/atheros/atl1e/atl1e_main.c", "atl1e_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl.c", "atlx_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl1.c", "atlx_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl2.c", "atl2_tx_timeout"],
["drivers/net/ethernet/broadcom/b44.c", "b44_tx_timeout"],
["drivers/net/ethernet/broadcom/bcmsysport.c", "bcm_sysport_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2.c", "bnx2_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnxt/bnxt.c", "bnxt_tx_timeout"],
["drivers/net/ethernet/broadcom/genet/bcmgenet.c", "bcmgenet_timeout"],
["drivers/net/ethernet/broadcom/sb1250-mac.c", "sbmac_tx_timeout"],
["drivers/net/ethernet/broadcom/tg3.c", "tg3_tx_timeout"],
["drivers/net/ethernet/calxeda/xgmac.c", "xgmac_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_main.c", "liquidio_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_vf_main.c", "liquidio_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c", "lio_vf_rep_tx_timeout"],
["drivers/net/ethernet/cavium/thunder/nicvf_main.c", "nicvf_tx_timeout"],
["drivers/net/ethernet/cirrus/cs89x0.c", "net_timeout"],
["drivers/net/ethernet/cisco/enic/enic_main.c", "enic_tx_timeout"],
["drivers/net/ethernet/cisco/enic/enic_main.c", "enic_tx_timeout"],
["drivers/net/ethernet/cortina/gemini.c", "gmac_tx_timeout"],
["drivers/net/ethernet/davicom/dm9000.c", "dm9000_timeout"],
["drivers/net/ethernet/dec/tulip/de2104x.c", "de_tx_timeout"],
["drivers/net/ethernet/dec/tulip/tulip_core.c", "tulip_tx_timeout"],
["drivers/net/ethernet/dec/tulip/winbond-840.c", "tx_timeout"],
["drivers/net/ethernet/dlink/dl2k.c", "rio_tx_timeout"],
["drivers/net/ethernet/dlink/sundance.c", "tx_timeout"],
["drivers/net/ethernet/emulex/benet/be_main.c", "be_tx_timeout"],
["drivers/net/ethernet/ethoc.c", "ethoc_tx_timeout"],
["drivers/net/ethernet/faraday/ftgmac100.c", "ftgmac100_tx_timeout"],
["drivers/net/ethernet/fealnx.c", "fealnx_tx_timeout"],
["drivers/net/ethernet/freescale/dpaa/dpaa_eth.c", "dpaa_tx_timeout"],
["drivers/net/ethernet/freescale/fec_main.c", "fec_timeout"],
["drivers/net/ethernet/freescale/fec_mpc52xx.c", "mpc52xx_fec_tx_timeout"],
["drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c", "fs_timeout"],
["drivers/net/ethernet/freescale/gianfar.c", "gfar_timeout"],
["drivers/net/ethernet/freescale/ucc_geth.c", "ucc_geth_timeout"],
["drivers/net/ethernet/fujitsu/fmvj18x_cs.c", "fjn_tx_timeout"],
["drivers/net/ethernet/google/gve/gve_main.c", "gve_tx_timeout"],
["drivers/net/ethernet/hisilicon/hip04_eth.c", "hip04_timeout"],
["drivers/net/ethernet/hisilicon/hix5hd2_gmac.c", "hix5hd2_net_timeout"],
["drivers/net/ethernet/hisilicon/hns/hns_enet.c", "hns_nic_net_timeout"],
["drivers/net/ethernet/hisilicon/hns3/hns3_enet.c", "hns3_nic_net_timeout"],
["drivers/net/ethernet/huawei/hinic/hinic_main.c", "hinic_tx_timeout"],
["drivers/net/ethernet/i825xx/82596.c", "i596_tx_timeout"],
["drivers/net/ethernet/i825xx/ether1.c", "ether1_timeout"],
["drivers/net/ethernet/i825xx/lib82596.c", "i596_tx_timeout"],
["drivers/net/ethernet/i825xx/sun3_82586.c", "sun3_82586_timeout"],
["drivers/net/ethernet/ibm/ehea/ehea_main.c", "ehea_tx_watchdog"],
["drivers/net/ethernet/ibm/emac/core.c", "emac_tx_timeout"],
["drivers/net/ethernet/ibm/emac/core.c", "emac_tx_timeout"],
["drivers/net/ethernet/ibm/ibmvnic.c", "ibmvnic_tx_timeout"],
["drivers/net/ethernet/intel/e100.c", "e100_tx_timeout"],
["drivers/net/ethernet/intel/e1000/e1000_main.c", "e1000_tx_timeout"],
["drivers/net/ethernet/intel/e1000e/netdev.c", "e1000_tx_timeout"],
["drivers/net/ethernet/intel/fm10k/fm10k_netdev.c", "fm10k_tx_timeout"],
["drivers/net/ethernet/intel/i40e/i40e_main.c", "i40e_tx_timeout"],
["drivers/net/ethernet/intel/iavf/iavf_main.c", "iavf_tx_timeout"],
["drivers/net/ethernet/intel/ice/ice_main.c", "ice_tx_timeout"],
["drivers/net/ethernet/intel/ice/ice_main.c", "ice_tx_timeout"],
["drivers/net/ethernet/intel/igb/igb_main.c", "igb_tx_timeout"],
["drivers/net/ethernet/intel/igbvf/netdev.c", "igbvf_tx_timeout"],
["drivers/net/ethernet/intel/ixgb/ixgb_main.c", "ixgb_tx_timeout"],
["drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c", "adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev);"],
["drivers/net/ethernet/intel/ixgbe/ixgbe_main.c", "ixgbe_tx_timeout"],
["drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c", "ixgbevf_tx_timeout"],
["drivers/net/ethernet/jme.c", "jme_tx_timeout"],
["drivers/net/ethernet/korina.c", "korina_tx_timeout"],
["drivers/net/ethernet/lantiq_etop.c", "ltq_etop_tx_timeout"],
["drivers/net/ethernet/marvell/mv643xx_eth.c", "mv643xx_eth_tx_timeout"],
["drivers/net/ethernet/marvell/pxa168_eth.c", "pxa168_eth_tx_timeout"],
["drivers/net/ethernet/marvell/skge.c", "skge_tx_timeout"],
["drivers/net/ethernet/marvell/sky2.c", "sky2_tx_timeout"],
["drivers/net/ethernet/marvell/sky2.c", "sky2_tx_timeout"],
["drivers/net/ethernet/mediatek/mtk_eth_soc.c", "mtk_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx4/en_netdev.c", "mlx4_en_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx4/en_netdev.c", "mlx4_en_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx5/core/en_main.c", "mlx5e_tx_timeout"],
["drivers/net/ethernet/micrel/ks8842.c", "ks8842_tx_timeout"],
["drivers/net/ethernet/micrel/ksz884x.c", "netdev_tx_timeout"],
["drivers/net/ethernet/microchip/enc28j60.c", "enc28j60_tx_timeout"],
["drivers/net/ethernet/microchip/encx24j600.c", "encx24j600_tx_timeout"],
["drivers/net/ethernet/natsemi/sonic.h", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/sonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/jazzsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/macsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/natsemi.c", "ns_tx_timeout"],
["drivers/net/ethernet/natsemi/ns83820.c", "ns83820_tx_timeout"],
["drivers/net/ethernet/natsemi/xtsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/neterion/s2io.h", "s2io_tx_watchdog"],
["drivers/net/ethernet/neterion/s2io.c", "s2io_tx_watchdog"],
["drivers/net/ethernet/neterion/vxge/vxge-main.c", "vxge_tx_watchdog"],
["drivers/net/ethernet/netronome/nfp/nfp_net_common.c", "nfp_net_tx_timeout"],
["drivers/net/ethernet/nvidia/forcedeth.c", "nv_tx_timeout"],
["drivers/net/ethernet/nvidia/forcedeth.c", "nv_tx_timeout"],
["drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c", "pch_gbe_tx_timeout"],
["drivers/net/ethernet/packetengines/hamachi.c", "hamachi_tx_timeout"],
["drivers/net/ethernet/packetengines/yellowfin.c", "yellowfin_tx_timeout"],
["drivers/net/ethernet/pensando/ionic/ionic_lif.c", "ionic_tx_timeout"],
["drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c", "netxen_tx_timeout"],
["drivers/net/ethernet/qlogic/qla3xxx.c", "ql3xxx_tx_timeout"],
["drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c", "qlcnic_tx_timeout"],
["drivers/net/ethernet/qualcomm/emac/emac.c", "emac_tx_timeout"],
["drivers/net/ethernet/qualcomm/qca_spi.c", "qcaspi_netdev_tx_timeout"],
["drivers/net/ethernet/qualcomm/qca_uart.c", "qcauart_netdev_tx_timeout"],
["drivers/net/ethernet/rdc/r6040.c", "r6040_tx_timeout"],
["drivers/net/ethernet/realtek/8139cp.c", "cp_tx_timeout"],
["drivers/net/ethernet/realtek/8139too.c", "rtl8139_tx_timeout"],
["drivers/net/ethernet/realtek/atp.c", "tx_timeout"],
["drivers/net/ethernet/realtek/r8169_main.c", "rtl8169_tx_timeout"],
["drivers/net/ethernet/renesas/ravb_main.c", "ravb_tx_timeout"],
["drivers/net/ethernet/renesas/sh_eth.c", "sh_eth_tx_timeout"],
["drivers/net/ethernet/renesas/sh_eth.c", "sh_eth_tx_timeout"],
["drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c", "sxgbe_tx_timeout"],
["drivers/net/ethernet/seeq/ether3.c", "ether3_timeout"],
["drivers/net/ethernet/seeq/sgiseeq.c", "timeout"],
["drivers/net/ethernet/sfc/efx.c", "efx_watchdog"],
["drivers/net/ethernet/sfc/falcon/efx.c", "ef4_watchdog"],
["drivers/net/ethernet/sgi/ioc3-eth.c", "ioc3_timeout"],
["drivers/net/ethernet/sgi/meth.c", "meth_tx_timeout"],
["drivers/net/ethernet/silan/sc92031.c", "sc92031_tx_timeout"],
["drivers/net/ethernet/sis/sis190.c", "sis190_tx_timeout"],
["drivers/net/ethernet/sis/sis900.c", "sis900_tx_timeout"],
["drivers/net/ethernet/smsc/epic100.c", "epic_tx_timeout"],
["drivers/net/ethernet/smsc/smc911x.c", "smc911x_timeout"],
["drivers/net/ethernet/smsc/smc9194.c", "smc_timeout"],
["drivers/net/ethernet/smsc/smc91c92_cs.c", "smc_tx_timeout"],
["drivers/net/ethernet/smsc/smc91x.c", "smc_timeout"],
["drivers/net/ethernet/stmicro/stmmac/stmmac_main.c", "stmmac_tx_timeout"],
["drivers/net/ethernet/sun/cassini.c", "cas_tx_timeout"],
["drivers/net/ethernet/sun/ldmvsw.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/niu.c", "niu_tx_timeout"],
["drivers/net/ethernet/sun/sunbmac.c", "bigmac_tx_timeout"],
["drivers/net/ethernet/sun/sungem.c", "gem_tx_timeout"],
["drivers/net/ethernet/sun/sunhme.c", "happy_meal_tx_timeout"],
["drivers/net/ethernet/sun/sunqe.c", "qe_tx_timeout"],
["drivers/net/ethernet/sun/sunvnet.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/sunvnet_common.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/sunvnet_common.h", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/synopsys/dwc-xlgmac-net.c", "xlgmac_tx_timeout"],
["drivers/net/ethernet/ti/cpmac.c", "cpmac_tx_timeout"],
["drivers/net/ethernet/ti/cpsw.c", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/cpsw_priv.c", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/cpsw_priv.h", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/davinci_emac.c", "emac_dev_tx_timeout"],
["drivers/net/ethernet/ti/netcp_core.c", "netcp_ndo_tx_timeout"],
["drivers/net/ethernet/ti/tlan.c", "tlan_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_net.h", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_net.c", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_wireless.c", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/spider_net.c", "spider_net_tx_timeout"],
["drivers/net/ethernet/toshiba/tc35815.c", "tc35815_tx_timeout"],
["drivers/net/ethernet/via/via-rhine.c", "rhine_tx_timeout"],
["drivers/net/ethernet/wiznet/w5100.c", "w5100_tx_timeout"],
["drivers/net/ethernet/wiznet/w5300.c", "w5300_tx_timeout"],
["drivers/net/ethernet/xilinx/xilinx_emaclite.c", "xemaclite_tx_timeout"],
["drivers/net/ethernet/xircom/xirc2ps_cs.c", "xirc_tx_timeout"],
["drivers/net/fjes/fjes_main.c", "fjes_tx_retry"],
["drivers/net/slip/slip.c", "sl_tx_timeout"],
["include/linux/usb/usbnet.h", "usbnet_tx_timeout"],
["drivers/net/usb/aqc111.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/ax88172a.c", "usbnet_tx_timeout"],
["drivers/net/usb/ax88179_178a.c", "usbnet_tx_timeout"],
["drivers/net/usb/catc.c", "catc_tx_timeout"],
["drivers/net/usb/cdc_mbim.c", "usbnet_tx_timeout"],
["drivers/net/usb/cdc_ncm.c", "usbnet_tx_timeout"],
["drivers/net/usb/dm9601.c", "usbnet_tx_timeout"],
["drivers/net/usb/hso.c", "hso_net_tx_timeout"],
["drivers/net/usb/int51x1.c", "usbnet_tx_timeout"],
["drivers/net/usb/ipheth.c", "ipheth_tx_timeout"],
["drivers/net/usb/kaweth.c", "kaweth_tx_timeout"],
["drivers/net/usb/lan78xx.c", "lan78xx_tx_timeout"],
["drivers/net/usb/mcs7830.c", "usbnet_tx_timeout"],
["drivers/net/usb/pegasus.c", "pegasus_tx_timeout"],
["drivers/net/usb/qmi_wwan.c", "usbnet_tx_timeout"],
["drivers/net/usb/r8152.c", "rtl8152_tx_timeout"],
["drivers/net/usb/rndis_host.c", "usbnet_tx_timeout"],
["drivers/net/usb/rtl8150.c", "rtl8150_tx_timeout"],
["drivers/net/usb/sierra_net.c", "usbnet_tx_timeout"],
["drivers/net/usb/smsc75xx.c", "usbnet_tx_timeout"],
["drivers/net/usb/smsc95xx.c", "usbnet_tx_timeout"],
["drivers/net/usb/sr9700.c", "usbnet_tx_timeout"],
["drivers/net/usb/sr9800.c", "usbnet_tx_timeout"],
["drivers/net/usb/usbnet.c", "usbnet_tx_timeout"],
["drivers/net/vmxnet3/vmxnet3_drv.c", "vmxnet3_tx_timeout"],
["drivers/net/wan/cosa.c", "cosa_net_timeout"],
["drivers/net/wan/farsync.c", "fst_tx_timeout"],
["drivers/net/wan/fsl_ucc_hdlc.c", "uhdlc_tx_timeout"],
["drivers/net/wan/lmc/lmc_main.c", "lmc_driver_timeout"],
["drivers/net/wan/x25_asy.c", "x25_asy_timeout"],
["drivers/net/wimax/i2400m/netdev.c", "i2400m_tx_timeout"],
["drivers/net/wireless/intel/ipw2x00/ipw2100.c", "ipw2100_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/main.c", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/orinoco_usb.c", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/orinoco.h", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_dev.c", "islpci_eth_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_eth.c", "islpci_eth_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_eth.h", "islpci_eth_tx_timeout"],
["drivers/net/wireless/marvell/mwifiex/main.c", "mwifiex_tx_timeout"],
["drivers/net/wireless/quantenna/qtnfmac/core.c", "qtnf_netdev_tx_timeout"],
["drivers/net/wireless/quantenna/qtnfmac/core.h", "qtnf_netdev_tx_timeout"],
["drivers/net/wireless/rndis_wlan.c", "usbnet_tx_timeout"],
["drivers/net/wireless/wl3501_cs.c", "wl3501_tx_timeout"],
["drivers/net/wireless/zydas/zd1201.c", "zd1201_tx_timeout"],
["drivers/s390/net/qeth_core.h", "qeth_tx_timeout"],
["drivers/s390/net/qeth_core_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l2_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l2_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l3_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l3_main.c", "qeth_tx_timeout"],
["drivers/staging/ks7010/ks_wlan_net.c", "ks_wlan_tx_timeout"],
["drivers/staging/qlge/qlge_main.c", "qlge_tx_timeout"],
["drivers/staging/rtl8192e/rtl8192e/rtl_core.c", "_rtl92e_tx_timeout"],
["drivers/staging/rtl8192u/r8192U_core.c", "tx_timeout"],
["drivers/staging/unisys/visornic/visornic_main.c", "visornic_xmit_timeout"],
["drivers/staging/wlan-ng/p80211netdev.c", "p80211knetdev_tx_timeout"],
["drivers/tty/n_gsm.c", "gsm_mux_net_tx_timeout"],
["drivers/tty/synclink.c", "hdlcdev_tx_timeout"],
["drivers/tty/synclink_gt.c", "hdlcdev_tx_timeout"],
["drivers/tty/synclinkmp.c", "hdlcdev_tx_timeout"],
["net/atm/lec.c", "lec_tx_timeout"],
["net/bluetooth/bnep/netdev.c", "bnep_net_timeout"]
);
for my $p (@work) {
my @pair = @$p;
my $file = $pair[0];
my $func = $pair[1];
print STDERR $file , ": ", $func,"\n";
our @ARGV = ($file);
while (<ARGV>) {
if (m/($func\s*\(struct\s+net_device\s+\*[A-Za-z_]?[A-Za-z-0-9_]*)(\))/) {
print STDERR "found $1+$2 in $file\n";
}
if (s/($func\s*\(struct\s+net_device\s+\*[A-Za-z_]?[A-Za-z-0-9_]*)(\))/$1, unsigned int txqueue$2/) {
print STDERR "$func found in $file\n";
}
print;
}
}
where the list of files and functions is simply from:
git grep ndo_tx_timeout, with manual addition of headers
in the rare cases where the function is from a header,
then manually changing the few places which actually
call ndo_tx_timeout.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Heiner Kallweit <hkallweit1@gmail.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Shannon Nelson <snelson@pensando.io>
Reviewed-by: Martin Habets <mhabets@solarflare.com>
changes from v9:
fixup a forward declaration
changes from v9:
more leftovers from v3 change
changes from v8:
fix up a missing direct call to timeout
rebased on net-next
changes from v7:
fixup leftovers from v3 change
changes from v6:
fix typo in rtl driver
changes from v5:
add missing files (allow any net device argument name)
changes from v4:
add a missing driver header
changes from v3:
change queue # to unsigned
Changes from v2:
added headers
Changes from v1:
Fix errors found by kbuild:
generalize the pattern a bit, to pick up
a couple of instances missed by the previous
version.
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-12-10 22:23:51 +08:00
|
|
|
static void qtnf_netdev_tx_timeout(struct net_device *ndev, unsigned int txqueue)
|
2017-05-12 05:51:01 +08:00
|
|
|
{
|
|
|
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
|
|
|
struct qtnf_wmac *mac;
|
|
|
|
struct qtnf_bus *bus;
|
|
|
|
|
|
|
|
if (unlikely(!vif || !vif->mac || !vif->mac->bus))
|
|
|
|
return;
|
|
|
|
|
|
|
|
mac = vif->mac;
|
|
|
|
bus = mac->bus;
|
|
|
|
|
|
|
|
pr_warn("VIF%u.%u: Tx timeout- %lu\n", mac->macid, vif->vifid, jiffies);
|
|
|
|
|
|
|
|
qtnf_bus_data_tx_timeout(bus, ndev);
|
|
|
|
ndev->stats.tx_errors++;
|
|
|
|
|
|
|
|
if (++vif->cons_tx_timeout_cnt > QTNF_TX_TIMEOUT_TRSHLD) {
|
|
|
|
pr_err("Tx timeout threshold exceeded !\n");
|
|
|
|
pr_err("schedule interface %s reset !\n", netdev_name(ndev));
|
|
|
|
queue_work(bus->workqueue, &vif->reset_work);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-31 17:10:57 +08:00
|
|
|
static int qtnf_netdev_set_mac_address(struct net_device *ndev, void *addr)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
|
|
|
struct sockaddr *sa = addr;
|
|
|
|
int ret;
|
|
|
|
unsigned char old_addr[ETH_ALEN];
|
|
|
|
|
|
|
|
memcpy(old_addr, sa->sa_data, sizeof(old_addr));
|
|
|
|
|
|
|
|
ret = eth_mac_addr(ndev, sa);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
qtnf_scan_done(vif->mac, true);
|
|
|
|
|
|
|
|
ret = qtnf_cmd_send_change_intf_type(vif, vif->wdev.iftype,
|
2019-01-14 17:39:38 +08:00
|
|
|
vif->wdev.use_4addr,
|
2018-05-31 17:10:57 +08:00
|
|
|
sa->sa_data);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
memcpy(ndev->dev_addr, old_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-11-18 16:23:10 +08:00
|
|
|
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;
|
|
|
|
|
|
|
|
ppid->id_len = sizeof(bus->hw_id);
|
|
|
|
memcpy(&ppid->id, bus->hw_id, ppid->id_len);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
/* Network device ops handlers */
|
|
|
|
const struct net_device_ops qtnf_netdev_ops = {
|
|
|
|
.ndo_open = qtnf_netdev_open,
|
|
|
|
.ndo_stop = qtnf_netdev_close,
|
|
|
|
.ndo_start_xmit = qtnf_netdev_hard_start_xmit,
|
|
|
|
.ndo_tx_timeout = qtnf_netdev_tx_timeout,
|
2018-01-22 20:46:26 +08:00
|
|
|
.ndo_get_stats64 = qtnf_netdev_get_stats64,
|
2018-05-31 17:10:57 +08:00
|
|
|
.ndo_set_mac_address = qtnf_netdev_set_mac_address,
|
2019-11-18 16:23:10 +08:00
|
|
|
.ndo_get_port_parent_id = qtnf_netdev_port_parent_id,
|
2017-05-12 05:51:01 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int qtnf_mac_init_single_band(struct wiphy *wiphy,
|
|
|
|
struct qtnf_wmac *mac,
|
|
|
|
enum nl80211_band band)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
wiphy->bands[band] = kzalloc(sizeof(*wiphy->bands[band]), GFP_KERNEL);
|
|
|
|
if (!wiphy->bands[band])
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
wiphy->bands[band]->band = band;
|
|
|
|
|
2017-10-31 09:04:47 +08:00
|
|
|
ret = qtnf_cmd_band_info_get(mac, wiphy->bands[band]);
|
2017-05-12 05:51:01 +08:00
|
|
|
if (ret) {
|
|
|
|
pr_err("MAC%u: band %u: failed to get chans info: %d\n",
|
|
|
|
mac->macid, band, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
qtnf_band_init_rates(wiphy->bands[band]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int qtnf_mac_init_bands(struct qtnf_wmac *mac)
|
|
|
|
{
|
|
|
|
struct wiphy *wiphy = priv_to_wiphy(mac);
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (mac->macinfo.bands_cap & QLINK_BAND_2GHZ) {
|
|
|
|
ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_2GHZ);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mac->macinfo.bands_cap & QLINK_BAND_5GHZ) {
|
|
|
|
ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_5GHZ);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mac->macinfo.bands_cap & QLINK_BAND_60GHZ)
|
|
|
|
ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_60GHZ);
|
|
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < QTNF_MAX_INTF; i++) {
|
|
|
|
vif = &mac->iflist[i];
|
|
|
|
if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
|
|
|
|
return vif;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif;
|
|
|
|
|
|
|
|
vif = &mac->iflist[QTNF_PRIMARY_VIF_IDX];
|
|
|
|
|
|
|
|
if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return vif;
|
|
|
|
}
|
|
|
|
|
2018-01-22 20:46:29 +08:00
|
|
|
void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac)
|
|
|
|
{
|
|
|
|
struct ieee80211_iface_combination *comb;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (mac->macinfo.if_comb) {
|
|
|
|
for (i = 0; i < mac->macinfo.n_if_comb; i++) {
|
|
|
|
comb = &mac->macinfo.if_comb[i];
|
|
|
|
kfree(comb->limits);
|
|
|
|
comb->limits = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(mac->macinfo.if_comb);
|
|
|
|
mac->macinfo.if_comb = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-05 18:11:38 +08:00
|
|
|
void qtnf_mac_ext_caps_free(struct qtnf_wmac *mac)
|
|
|
|
{
|
|
|
|
if (mac->macinfo.extended_capabilities_len) {
|
|
|
|
kfree(mac->macinfo.extended_capabilities);
|
|
|
|
mac->macinfo.extended_capabilities = NULL;
|
|
|
|
|
|
|
|
kfree(mac->macinfo.extended_capabilities_mask);
|
|
|
|
mac->macinfo.extended_capabilities_mask = NULL;
|
|
|
|
|
|
|
|
mac->macinfo.extended_capabilities_len = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
static void qtnf_vif_reset_handler(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_work);
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
|
|
|
if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) {
|
|
|
|
rtnl_unlock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stop tx completely */
|
|
|
|
netif_tx_stop_all_queues(vif->netdev);
|
|
|
|
if (netif_carrier_ok(vif->netdev))
|
|
|
|
netif_carrier_off(vif->netdev);
|
|
|
|
|
|
|
|
qtnf_cfg80211_vif_reset(vif);
|
|
|
|
|
|
|
|
rtnl_unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qtnf_mac_init_primary_intf(struct qtnf_wmac *mac)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif = &mac->iflist[QTNF_PRIMARY_VIF_IDX];
|
|
|
|
|
2017-12-19 19:28:50 +08:00
|
|
|
vif->wdev.iftype = NL80211_IFTYPE_STATION;
|
2017-05-12 05:51:01 +08:00
|
|
|
vif->bss_priority = QTNF_DEF_BSS_PRIORITY;
|
|
|
|
vif->wdev.wiphy = priv_to_wiphy(mac);
|
|
|
|
INIT_WORK(&vif->reset_work, qtnf_vif_reset_handler);
|
|
|
|
vif->cons_tx_timeout_cnt = 0;
|
|
|
|
}
|
|
|
|
|
2018-01-22 20:46:32 +08:00
|
|
|
static void qtnf_mac_scan_finish(struct qtnf_wmac *mac, bool aborted)
|
|
|
|
{
|
|
|
|
struct cfg80211_scan_info info = {
|
|
|
|
.aborted = aborted,
|
|
|
|
};
|
|
|
|
|
|
|
|
mutex_lock(&mac->mac_lock);
|
|
|
|
|
|
|
|
if (mac->scan_req) {
|
|
|
|
cfg80211_scan_done(mac->scan_req, &info);
|
|
|
|
mac->scan_req = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&mac->mac_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted)
|
|
|
|
{
|
|
|
|
cancel_delayed_work_sync(&mac->scan_timeout);
|
|
|
|
qtnf_mac_scan_finish(mac, aborted);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qtnf_mac_scan_timeout(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct qtnf_wmac *mac =
|
|
|
|
container_of(work, struct qtnf_wmac, scan_timeout.work);
|
|
|
|
|
|
|
|
pr_warn("MAC%d: scan timed out\n", mac->macid);
|
|
|
|
qtnf_mac_scan_finish(mac, true);
|
|
|
|
}
|
|
|
|
|
2019-03-20 18:04:09 +08:00
|
|
|
static void qtnf_vif_send_data_high_pri(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif =
|
|
|
|
container_of(work, struct qtnf_vif, high_pri_tx_work);
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (!vif->netdev ||
|
|
|
|
vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while ((skb = skb_dequeue(&vif->high_pri_tx_queue))) {
|
|
|
|
qtnf_cmd_send_frame(vif, 0, QLINK_FRAME_TX_FLAG_8023,
|
|
|
|
0, skb->data, skb->len);
|
|
|
|
dev_kfree_skb_any(skb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
|
|
|
|
unsigned int macid)
|
|
|
|
{
|
2020-02-13 19:45:31 +08:00
|
|
|
struct platform_device *pdev = NULL;
|
|
|
|
struct qtnf_wmac *mac;
|
2018-10-05 18:11:31 +08:00
|
|
|
struct qtnf_vif *vif;
|
2017-05-12 05:51:01 +08:00
|
|
|
struct wiphy *wiphy;
|
|
|
|
unsigned int i;
|
|
|
|
|
2020-02-13 19:45:31 +08:00
|
|
|
if (bus->hw_info.num_mac > 1) {
|
|
|
|
pdev = platform_device_register_data(bus->dev,
|
|
|
|
dev_name(bus->dev),
|
|
|
|
macid, NULL, 0);
|
|
|
|
if (IS_ERR(pdev))
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
wiphy = qtnf_wiphy_allocate(bus, pdev);
|
2017-05-12 05:51:01 +08:00
|
|
|
if (!wiphy)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
mac = wiphy_priv(wiphy);
|
|
|
|
|
|
|
|
mac->macid = macid;
|
2020-02-13 19:45:31 +08:00
|
|
|
mac->pdev = pdev;
|
2017-05-12 05:51:01 +08:00
|
|
|
mac->bus = bus;
|
2018-10-05 18:11:31 +08:00
|
|
|
mutex_init(&mac->mac_lock);
|
|
|
|
INIT_DELAYED_WORK(&mac->scan_timeout, qtnf_mac_scan_timeout);
|
2017-05-12 05:51:01 +08:00
|
|
|
|
|
|
|
for (i = 0; i < QTNF_MAX_INTF; i++) {
|
2018-10-05 18:11:31 +08:00
|
|
|
vif = &mac->iflist[i];
|
|
|
|
|
|
|
|
memset(vif, 0, sizeof(*vif));
|
|
|
|
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
|
|
|
vif->mac = mac;
|
|
|
|
vif->vifid = i;
|
|
|
|
qtnf_sta_list_init(&vif->sta_list);
|
2019-03-20 18:04:09 +08:00
|
|
|
INIT_WORK(&vif->high_pri_tx_work, qtnf_vif_send_data_high_pri);
|
|
|
|
skb_queue_head_init(&vif->high_pri_tx_queue);
|
2018-10-05 18:11:31 +08:00
|
|
|
vif->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
|
|
|
if (!vif->stats64)
|
2018-01-22 20:46:26 +08:00
|
|
|
pr_warn("VIF%u.%u: per cpu stats allocation failed\n",
|
|
|
|
macid, i);
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
qtnf_mac_init_primary_intf(mac);
|
|
|
|
bus->mac[macid] = mac;
|
|
|
|
|
|
|
|
return mac;
|
|
|
|
}
|
|
|
|
|
2018-01-22 20:46:28 +08:00
|
|
|
static const struct ethtool_ops qtnf_ethtool_ops = {
|
|
|
|
.get_drvinfo = cfg80211_get_drvinfo,
|
|
|
|
};
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
|
2017-12-19 19:28:50 +08:00
|
|
|
const char *name, unsigned char name_assign_type)
|
2017-05-12 05:51:01 +08:00
|
|
|
{
|
|
|
|
struct wiphy *wiphy = priv_to_wiphy(mac);
|
|
|
|
struct net_device *dev;
|
|
|
|
void *qdev_vif;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
dev = alloc_netdev_mqs(sizeof(struct qtnf_vif *), name,
|
|
|
|
name_assign_type, ether_setup, 1, 1);
|
2019-11-18 16:23:04 +08:00
|
|
|
if (!dev)
|
2017-05-12 05:51:01 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
vif->netdev = dev;
|
|
|
|
|
|
|
|
dev->netdev_ops = &qtnf_netdev_ops;
|
2017-06-15 23:31:37 +08:00
|
|
|
dev->needs_free_netdev = true;
|
2017-05-12 05:51:01 +08:00
|
|
|
dev_net_set(dev, wiphy_net(wiphy));
|
|
|
|
dev->ieee80211_ptr = &vif->wdev;
|
|
|
|
ether_addr_copy(dev->dev_addr, vif->mac_addr);
|
|
|
|
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
|
|
|
|
dev->watchdog_timeo = QTNF_DEF_WDOG_TIMEOUT;
|
|
|
|
dev->tx_queue_len = 100;
|
2018-01-22 20:46:28 +08:00
|
|
|
dev->ethtool_ops = &qtnf_ethtool_ops;
|
2017-05-12 05:51:01 +08:00
|
|
|
|
2020-01-27 18:46:46 +08:00
|
|
|
if (qtnf_hwcap_is_set(&mac->bus->hw_info, QLINK_HW_CAPAB_HW_BRIDGE))
|
2019-11-18 16:23:08 +08:00
|
|
|
dev->needed_tailroom = sizeof(struct qtnf_frame_meta_info);
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
qdev_vif = netdev_priv(dev);
|
|
|
|
*((void **)qdev_vif) = vif;
|
|
|
|
|
2020-02-13 19:45:31 +08:00
|
|
|
SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
|
2017-05-12 05:51:01 +08:00
|
|
|
|
|
|
|
ret = register_netdevice(dev);
|
|
|
|
if (ret) {
|
|
|
|
free_netdev(dev);
|
2019-11-18 16:23:04 +08:00
|
|
|
vif->netdev = NULL;
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
|
|
|
|
{
|
|
|
|
struct qtnf_wmac *mac;
|
|
|
|
struct wiphy *wiphy;
|
|
|
|
struct qtnf_vif *vif;
|
|
|
|
unsigned int i;
|
|
|
|
enum nl80211_band band;
|
|
|
|
|
|
|
|
mac = bus->mac[macid];
|
|
|
|
|
|
|
|
if (!mac)
|
|
|
|
return;
|
|
|
|
|
|
|
|
wiphy = priv_to_wiphy(mac);
|
|
|
|
|
|
|
|
for (i = 0; i < QTNF_MAX_INTF; i++) {
|
|
|
|
vif = &mac->iflist[i];
|
|
|
|
rtnl_lock();
|
|
|
|
if (vif->netdev &&
|
|
|
|
vif->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) {
|
|
|
|
qtnf_virtual_intf_cleanup(vif->netdev);
|
|
|
|
qtnf_del_virtual_intf(wiphy, &vif->wdev);
|
|
|
|
}
|
|
|
|
rtnl_unlock();
|
|
|
|
qtnf_sta_list_free(&vif->sta_list);
|
2018-01-22 20:46:26 +08:00
|
|
|
free_percpu(vif->stats64);
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mac->wiphy_registered)
|
|
|
|
wiphy_unregister(wiphy);
|
|
|
|
|
|
|
|
for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; ++band) {
|
|
|
|
if (!wiphy->bands[band])
|
|
|
|
continue;
|
|
|
|
|
2019-11-18 16:23:16 +08:00
|
|
|
kfree(wiphy->bands[band]->iftype_data);
|
|
|
|
wiphy->bands[band]->n_iftype_data = 0;
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
kfree(wiphy->bands[band]->channels);
|
|
|
|
wiphy->bands[band]->n_channels = 0;
|
|
|
|
|
|
|
|
kfree(wiphy->bands[band]);
|
|
|
|
wiphy->bands[band] = NULL;
|
|
|
|
}
|
|
|
|
|
2020-02-13 19:45:31 +08:00
|
|
|
platform_device_unregister(mac->pdev);
|
2018-01-22 20:46:29 +08:00
|
|
|
qtnf_mac_iface_comb_free(mac);
|
2018-10-05 18:11:38 +08:00
|
|
|
qtnf_mac_ext_caps_free(mac);
|
2018-08-02 18:40:43 +08:00
|
|
|
kfree(mac->macinfo.wowlan);
|
2019-03-20 18:03:57 +08:00
|
|
|
kfree(mac->rd);
|
|
|
|
mac->rd = NULL;
|
2017-05-12 05:51:01 +08:00
|
|
|
wiphy_free(wiphy);
|
|
|
|
bus->mac[macid] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid)
|
|
|
|
{
|
|
|
|
struct qtnf_wmac *mac;
|
|
|
|
struct qtnf_vif *vif;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!(bus->hw_info.mac_bitmap & BIT(macid))) {
|
|
|
|
pr_info("MAC%u is not active in FW\n", macid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
mac = qtnf_core_mac_alloc(bus, macid);
|
|
|
|
if (IS_ERR(mac)) {
|
|
|
|
pr_err("MAC%u allocation failed\n", macid);
|
|
|
|
return PTR_ERR(mac);
|
|
|
|
}
|
|
|
|
|
|
|
|
vif = qtnf_mac_get_base_vif(mac);
|
|
|
|
if (!vif) {
|
|
|
|
pr_err("MAC%u: primary VIF is not ready\n", macid);
|
|
|
|
ret = -EFAULT;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-01-14 17:39:38 +08:00
|
|
|
ret = qtnf_cmd_send_add_intf(vif, vif->wdev.iftype,
|
|
|
|
vif->wdev.use_4addr, vif->mac_addr);
|
2017-05-12 05:51:01 +08:00
|
|
|
if (ret) {
|
|
|
|
pr_err("MAC%u: failed to add VIF\n", macid);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2020-01-27 18:46:47 +08:00
|
|
|
ret = qtnf_cmd_get_mac_info(mac);
|
2017-05-12 05:51:01 +08:00
|
|
|
if (ret) {
|
2020-01-27 18:46:47 +08:00
|
|
|
pr_err("MAC%u: failed to get MAC info\n", macid);
|
2019-11-18 16:23:04 +08:00
|
|
|
goto error_del_vif;
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
2020-01-27 18:46:47 +08:00
|
|
|
/* 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);
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
ret = qtnf_mac_init_bands(mac);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("MAC%u: failed to init bands\n", macid);
|
2019-11-18 16:23:04 +08:00
|
|
|
goto error_del_vif;
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = qtnf_wiphy_register(&bus->hw_info, mac);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("MAC%u: wiphy registration failed\n", macid);
|
2019-11-18 16:23:04 +08:00
|
|
|
goto error_del_vif;
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mac->wiphy_registered = 1;
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
2017-12-19 19:28:50 +08:00
|
|
|
ret = qtnf_core_net_attach(mac, vif, "wlan%d", NET_NAME_ENUM);
|
2017-05-12 05:51:01 +08:00
|
|
|
rtnl_unlock();
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("MAC%u: failed to attach netdev\n", macid);
|
2019-11-18 16:23:04 +08:00
|
|
|
goto error_del_vif;
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
2020-01-27 18:46:46 +08:00
|
|
|
if (qtnf_hwcap_is_set(&bus->hw_info, QLINK_HW_CAPAB_HW_BRIDGE)) {
|
2019-11-18 16:23:06 +08:00
|
|
|
ret = qtnf_cmd_netdev_changeupper(vif, vif->netdev->ifindex);
|
|
|
|
if (ret)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
pr_debug("MAC%u initialized\n", macid);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2019-11-18 16:23:04 +08:00
|
|
|
error_del_vif:
|
|
|
|
qtnf_cmd_send_del_intf(vif);
|
|
|
|
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
2017-05-12 05:51:01 +08:00
|
|
|
error:
|
|
|
|
qtnf_core_mac_detach(bus, macid);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-11-18 16:23:06 +08:00
|
|
|
bool qtnf_netdev_is_qtn(const struct net_device *ndev)
|
|
|
|
{
|
|
|
|
return ndev->netdev_ops == &qtnf_netdev_ops;
|
|
|
|
}
|
|
|
|
|
2020-01-09 21:17:53 +08:00
|
|
|
static int qtnf_check_br_ports(struct net_device *dev, void *data)
|
|
|
|
{
|
|
|
|
struct net_device *ndev = data;
|
|
|
|
|
|
|
|
if (dev != ndev && netdev_port_same_parent_id(dev, ndev))
|
|
|
|
return -ENOTSUPP;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-18 16:23:06 +08:00
|
|
|
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;
|
2020-01-09 21:17:53 +08:00
|
|
|
struct net_device *brdev;
|
2019-11-18 16:23:06 +08:00
|
|
|
struct qtnf_vif *vif;
|
2020-01-09 21:17:53 +08:00
|
|
|
struct qtnf_bus *bus;
|
2019-11-18 16:23:06 +08:00
|
|
|
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);
|
2020-01-09 21:17:53 +08:00
|
|
|
bus = vif->mac->bus;
|
2019-11-18 16:23:06 +08:00
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case NETDEV_CHANGEUPPER:
|
|
|
|
info = ptr;
|
2020-01-09 21:17:53 +08:00
|
|
|
brdev = info->upper_dev;
|
2019-11-18 16:23:06 +08:00
|
|
|
|
2020-01-09 21:17:53 +08:00
|
|
|
if (!netif_is_bridge_master(brdev))
|
2019-11-18 16:23:06 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
pr_debug("[VIF%u.%u] change bridge: %s %s\n",
|
2020-01-09 21:17:53 +08:00
|
|
|
vif->mac->macid, vif->vifid, netdev_name(brdev),
|
2019-11-18 16:23:06 +08:00
|
|
|
info->linking ? "add" : "del");
|
|
|
|
|
2020-01-09 21:17:53 +08:00
|
|
|
if (IS_ENABLED(CONFIG_NET_SWITCHDEV) &&
|
2020-01-27 18:46:46 +08:00
|
|
|
qtnf_hwcap_is_set(&bus->hw_info,
|
|
|
|
QLINK_HW_CAPAB_HW_BRIDGE)) {
|
2020-01-09 21:17:53 +08:00
|
|
|
if (info->linking)
|
|
|
|
br_domain = brdev->ifindex;
|
|
|
|
else
|
|
|
|
br_domain = ndev->ifindex;
|
|
|
|
|
|
|
|
ret = qtnf_cmd_netdev_changeupper(vif, br_domain);
|
|
|
|
} else {
|
|
|
|
ret = netdev_walk_all_lower_dev(brdev,
|
|
|
|
qtnf_check_br_ports,
|
|
|
|
ndev);
|
|
|
|
}
|
2019-11-18 16:23:06 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return notifier_from_errno(ret);
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
int qtnf_core_attach(struct qtnf_bus *bus)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
qtnf_trans_init(bus);
|
|
|
|
qtnf_bus_data_rx_start(bus);
|
|
|
|
|
|
|
|
bus->workqueue = alloc_ordered_workqueue("QTNF_BUS", 0);
|
|
|
|
if (!bus->workqueue) {
|
|
|
|
pr_err("failed to alloc main workqueue\n");
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-03-20 18:04:09 +08:00
|
|
|
bus->hprio_workqueue = alloc_workqueue("QTNF_HPRI", WQ_HIGHPRI, 0);
|
|
|
|
if (!bus->hprio_workqueue) {
|
|
|
|
pr_err("failed to alloc high prio workqueue\n");
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
INIT_WORK(&bus->event_work, qtnf_event_work_handler);
|
|
|
|
|
|
|
|
ret = qtnf_cmd_send_init_fw(bus);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("failed to init FW: %d\n", ret);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2020-01-27 18:46:44 +08:00
|
|
|
if (QLINK_VER_MAJOR(bus->hw_info.ql_proto_ver) !=
|
|
|
|
QLINK_PROTO_VER_MAJOR) {
|
|
|
|
pr_err("qlink driver vs FW version mismatch: %u vs %u\n",
|
|
|
|
QLINK_PROTO_VER_MAJOR,
|
|
|
|
QLINK_VER_MAJOR(bus->hw_info.ql_proto_ver));
|
|
|
|
ret = -EPROTONOSUPPORT;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
bus->fw_state = QTNF_FW_STATE_ACTIVE;
|
|
|
|
ret = qtnf_cmd_get_hw_info(bus);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("failed to get HW info: %d\n", ret);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2020-01-27 18:46:46 +08:00
|
|
|
if (qtnf_hwcap_is_set(&bus->hw_info, QLINK_HW_CAPAB_HW_BRIDGE) &&
|
2019-11-18 16:23:08 +08:00
|
|
|
bus->bus_ops->data_tx_use_meta_set)
|
|
|
|
bus->bus_ops->data_tx_use_meta_set(bus, true);
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
if (bus->hw_info.num_mac > QTNF_MAX_MAC) {
|
|
|
|
pr_err("no support for number of MACs=%u\n",
|
|
|
|
bus->hw_info.num_mac);
|
|
|
|
ret = -ERANGE;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < bus->hw_info.num_mac; i++) {
|
|
|
|
ret = qtnf_core_mac_attach(bus, i);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("MAC%u: attach failed: %d\n", i, ret);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-09 21:17:53 +08:00
|
|
|
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;
|
2019-11-18 16:23:06 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 18:04:04 +08:00
|
|
|
bus->fw_state = QTNF_FW_STATE_RUNNING;
|
2017-05-12 05:51:01 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
qtnf_core_detach(bus);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(qtnf_core_attach);
|
|
|
|
|
|
|
|
void qtnf_core_detach(struct qtnf_bus *bus)
|
|
|
|
{
|
|
|
|
unsigned int macid;
|
|
|
|
|
2019-11-18 16:23:06 +08:00
|
|
|
unregister_netdevice_notifier(&bus->netdev_nb);
|
2017-05-12 05:51:01 +08:00
|
|
|
qtnf_bus_data_rx_stop(bus);
|
|
|
|
|
|
|
|
for (macid = 0; macid < QTNF_MAX_MAC; macid++)
|
|
|
|
qtnf_core_mac_detach(bus, macid);
|
|
|
|
|
2019-03-20 18:04:04 +08:00
|
|
|
if (qtnf_fw_is_up(bus))
|
2017-05-12 05:51:01 +08:00
|
|
|
qtnf_cmd_send_deinit_fw(bus);
|
|
|
|
|
2018-05-29 20:00:01 +08:00
|
|
|
bus->fw_state = QTNF_FW_STATE_DETACHED;
|
2017-05-12 05:51:01 +08:00
|
|
|
|
|
|
|
if (bus->workqueue) {
|
|
|
|
flush_workqueue(bus->workqueue);
|
|
|
|
destroy_workqueue(bus->workqueue);
|
2019-03-20 18:04:09 +08:00
|
|
|
bus->workqueue = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus->hprio_workqueue) {
|
|
|
|
flush_workqueue(bus->hprio_workqueue);
|
|
|
|
destroy_workqueue(bus->hprio_workqueue);
|
|
|
|
bus->hprio_workqueue = NULL;
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
qtnf_trans_free(bus);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(qtnf_core_detach);
|
|
|
|
|
|
|
|
static inline int qtnf_is_frame_meta_magic_valid(struct qtnf_frame_meta_info *m)
|
|
|
|
{
|
2019-11-18 16:23:08 +08:00
|
|
|
return m->magic_s == HBM_FRAME_META_MAGIC_PATTERN_S &&
|
|
|
|
m->magic_e == HBM_FRAME_META_MAGIC_PATTERN_E;
|
2017-05-12 05:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct qtnf_frame_meta_info *meta;
|
|
|
|
struct net_device *ndev = NULL;
|
|
|
|
struct qtnf_wmac *mac;
|
|
|
|
struct qtnf_vif *vif;
|
|
|
|
|
2019-03-20 18:04:04 +08:00
|
|
|
if (unlikely(bus->fw_state != QTNF_FW_STATE_RUNNING))
|
|
|
|
return NULL;
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
meta = (struct qtnf_frame_meta_info *)
|
|
|
|
(skb_tail_pointer(skb) - sizeof(*meta));
|
|
|
|
|
|
|
|
if (unlikely(!qtnf_is_frame_meta_magic_valid(meta))) {
|
|
|
|
pr_err_ratelimited("invalid magic 0x%x:0x%x\n",
|
|
|
|
meta->magic_s, meta->magic_e);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlikely(meta->macid >= QTNF_MAX_MAC)) {
|
|
|
|
pr_err_ratelimited("invalid mac(%u)\n", meta->macid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlikely(meta->ifidx >= QTNF_MAX_INTF)) {
|
|
|
|
pr_err_ratelimited("invalid vif(%u)\n", meta->ifidx);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
mac = bus->mac[meta->macid];
|
|
|
|
|
|
|
|
if (unlikely(!mac)) {
|
|
|
|
pr_err_ratelimited("mac(%d) does not exist\n", meta->macid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
vif = &mac->iflist[meta->ifidx];
|
|
|
|
|
|
|
|
if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)) {
|
|
|
|
pr_err_ratelimited("vif(%u) does not exists\n", meta->ifidx);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ndev = vif->netdev;
|
|
|
|
|
|
|
|
if (unlikely(!ndev)) {
|
|
|
|
pr_err_ratelimited("netdev for wlan%u.%u does not exists\n",
|
|
|
|
meta->macid, meta->ifidx);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
__skb_trim(skb, skb->len - sizeof(*meta));
|
2019-11-18 16:23:12 +08:00
|
|
|
/* Firmware always handles packets that require flooding */
|
|
|
|
qtnfmac_switch_mark_skb_flooded(skb);
|
2017-05-12 05:51:01 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
return ndev;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(qtnf_classify_skb);
|
|
|
|
|
2017-10-30 18:13:49 +08:00
|
|
|
void qtnf_wake_all_queues(struct net_device *ndev)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
|
|
|
struct qtnf_wmac *mac;
|
|
|
|
struct qtnf_bus *bus;
|
|
|
|
int macid;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (unlikely(!vif || !vif->mac || !vif->mac->bus))
|
|
|
|
return;
|
|
|
|
|
|
|
|
bus = vif->mac->bus;
|
|
|
|
|
|
|
|
for (macid = 0; macid < QTNF_MAX_MAC; macid++) {
|
|
|
|
if (!(bus->hw_info.mac_bitmap & BIT(macid)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
mac = bus->mac[macid];
|
|
|
|
for (i = 0; i < QTNF_MAX_INTF; i++) {
|
|
|
|
vif = &mac->iflist[i];
|
|
|
|
if (vif->netdev && netif_queue_stopped(vif->netdev))
|
|
|
|
netif_tx_wake_all_queues(vif->netdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(qtnf_wake_all_queues);
|
|
|
|
|
2018-01-22 20:46:26 +08:00
|
|
|
void qtnf_update_rx_stats(struct net_device *ndev, const struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
|
|
|
struct pcpu_sw_netstats *stats64;
|
|
|
|
|
|
|
|
if (unlikely(!vif || !vif->stats64)) {
|
|
|
|
ndev->stats.rx_packets++;
|
|
|
|
ndev->stats.rx_bytes += skb->len;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
stats64 = this_cpu_ptr(vif->stats64);
|
|
|
|
|
|
|
|
u64_stats_update_begin(&stats64->syncp);
|
|
|
|
stats64->rx_packets++;
|
|
|
|
stats64->rx_bytes += skb->len;
|
|
|
|
u64_stats_update_end(&stats64->syncp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(qtnf_update_rx_stats);
|
|
|
|
|
|
|
|
void qtnf_update_tx_stats(struct net_device *ndev, const struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
|
|
|
struct pcpu_sw_netstats *stats64;
|
|
|
|
|
|
|
|
if (unlikely(!vif || !vif->stats64)) {
|
|
|
|
ndev->stats.tx_packets++;
|
|
|
|
ndev->stats.tx_bytes += skb->len;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
stats64 = this_cpu_ptr(vif->stats64);
|
|
|
|
|
|
|
|
u64_stats_update_begin(&stats64->syncp);
|
|
|
|
stats64->tx_packets++;
|
|
|
|
stats64->tx_bytes += skb->len;
|
|
|
|
u64_stats_update_end(&stats64->syncp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(qtnf_update_tx_stats);
|
|
|
|
|
2019-04-09 15:35:12 +08:00
|
|
|
struct dentry *qtnf_get_debugfs_dir(void)
|
|
|
|
{
|
|
|
|
return qtnf_debugfs_dir;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(qtnf_get_debugfs_dir);
|
|
|
|
|
|
|
|
static int __init qtnf_core_register(void)
|
|
|
|
{
|
|
|
|
qtnf_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
|
|
|
|
|
|
|
|
if (IS_ERR(qtnf_debugfs_dir))
|
|
|
|
qtnf_debugfs_dir = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit qtnf_core_exit(void)
|
|
|
|
{
|
|
|
|
debugfs_remove(qtnf_debugfs_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(qtnf_core_register);
|
|
|
|
module_exit(qtnf_core_exit);
|
|
|
|
|
2017-05-12 05:51:01 +08:00
|
|
|
MODULE_AUTHOR("Quantenna Communications");
|
|
|
|
MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver.");
|
|
|
|
MODULE_LICENSE("GPL");
|