Merge tag 'mlx5-updates-2021-04-13' of git://git.kernel.org/pub/scm/linux/kernel...
authorDavid S. Miller <davem@davemloft.net>
Wed, 14 Apr 2021 21:14:03 +0000 (14:14 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 14 Apr 2021 21:14:03 +0000 (14:14 -0700)
Saeed Mahameed says:

====================
mlx5-updates-2021-04-13

mlx5 core and netdev driver updates

1) E-Switch updates from Parav,
  1.1) Devlink parameter to control mlx5 metadata enablement for E-Switch
  1.2) Trivial cleanups for E-Switch code
  1.3) Dynamically allocate vport steering namespaces only when required

2) From Jianbo, Use variably sized data structures for Software steering

3) Several minor cleanups
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
195 files changed:
Documentation/devicetree/bindings/net/can/rcar_can.txt
Documentation/devicetree/bindings/net/qcom,ipa.yaml
arch/arm/mach-mvebu/kirkwood.c
arch/powerpc/sysdev/tsi108_dev.c
drivers/atm/idt77252.c
drivers/net/Space.c
drivers/net/can/usb/Kconfig
drivers/net/can/usb/Makefile
drivers/net/can/usb/etas_es58x/Makefile [new file with mode: 0644]
drivers/net/can/usb/etas_es58x/es581_4.c [new file with mode: 0644]
drivers/net/can/usb/etas_es58x/es581_4.h [new file with mode: 0644]
drivers/net/can/usb/etas_es58x/es58x_core.c [new file with mode: 0644]
drivers/net/can/usb/etas_es58x/es58x_core.h [new file with mode: 0644]
drivers/net/can/usb/etas_es58x/es58x_fd.c [new file with mode: 0644]
drivers/net/can/usb/etas_es58x/es58x_fd.h [new file with mode: 0644]
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_core.c
drivers/net/can/usb/peak_usb/pcan_usb_core.h
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.h
drivers/net/dsa/mt7530.c
drivers/net/dsa/mt7530.h
drivers/net/ethernet/aeroflex/greth.c
drivers/net/ethernet/allwinner/sun4i-emac.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/atheros/ag71xx.c
drivers/net/ethernet/broadcom/bcm4908_enet.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bgmac-bcma.c
drivers/net/ethernet/broadcom/bgmac-platform.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
drivers/net/ethernet/cavium/thunder/thunder_bgx.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/ethoc.c
drivers/net/ethernet/ezchip/nps_enet.c
drivers/net/ethernet/freescale/dpaa2/Makefile
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c [new file with mode: 0644]
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
drivers/net/ethernet/freescale/dpaa2/dpsw-cmd.h
drivers/net/ethernet/freescale/dpaa2/dpsw.c
drivers/net/ethernet/freescale/dpaa2/dpsw.h
drivers/net/ethernet/freescale/enetc/enetc_pf.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_mpc52xx.c
drivers/net/ethernet/freescale/fman/mac.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/hisilicon/hisi_femac.c
drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbevf/vf.h
drivers/net/ethernet/lantiq_xrx200.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/prestera/prestera_main.c
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/micrel/ks8851_common.c
drivers/net/ethernet/microchip/lan743x_main.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
drivers/net/ethernet/pensando/ionic/ionic_phc.c
drivers/net/ethernet/qualcomm/qca_spi.c
drivers/net/ethernet/qualcomm/qca_uart.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
drivers/net/ethernet/sfc/enum.h
drivers/net/ethernet/socionext/sni_ave.c
drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c
drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
drivers/net/ethernet/stmicro/stmmac/hwif.h
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.h
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/cpsw_new.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/ti/netcp_core.c
drivers/net/ethernet/wiznet/w5100-spi.c
drivers/net/ethernet/wiznet/w5100.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/ethernet/xilinx/xilinx_axienet_main.c
drivers/net/ethernet/xilinx/xilinx_emaclite.c
drivers/net/ipa/Makefile
drivers/net/ipa/ipa_data-v4.9.c [new file with mode: 0644]
drivers/net/ipa/ipa_data.h
drivers/net/ipa/ipa_main.c
drivers/net/phy/marvell-88x2222.c
drivers/net/wireless/ath/ath10k/snoc.c
drivers/net/wireless/ath/ath11k/ahb.c
drivers/net/wireless/ath/ath11k/ce.c
drivers/net/wireless/ath/ath11k/ce.h
drivers/net/wireless/ath/ath11k/core.c
drivers/net/wireless/ath/ath11k/core.h
drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
drivers/net/wireless/ath/ath11k/dp_rx.c
drivers/net/wireless/ath/ath11k/dp_tx.c
drivers/net/wireless/ath/ath11k/hal.c
drivers/net/wireless/ath/ath11k/hal.h
drivers/net/wireless/ath/ath11k/hal_desc.h
drivers/net/wireless/ath/ath11k/hal_tx.c
drivers/net/wireless/ath/ath11k/hal_tx.h
drivers/net/wireless/ath/ath11k/hif.h
drivers/net/wireless/ath/ath11k/hw.c
drivers/net/wireless/ath/ath11k/hw.h
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/mac.h
drivers/net/wireless/ath/ath11k/mhi.c
drivers/net/wireless/ath/ath11k/pci.c
drivers/net/wireless/ath/ath11k/pci.h
drivers/net/wireless/ath/ath11k/qmi.c
drivers/net/wireless/ath/ath11k/qmi.h
drivers/net/wireless/ath/ath11k/rx_desc.h
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/intel/iwlegacy/3945-mac.c
drivers/net/wireless/intel/iwlegacy/common.c
drivers/net/wireless/intel/iwlegacy/common.h
drivers/net/wireless/mediatek/mt76/eeprom.c
drivers/net/wireless/mediatek/mt7601u/eeprom.c
drivers/net/wireless/mediatek/mt7601u/init.c
drivers/net/wireless/microchip/wilc1000/netdev.c
drivers/net/wireless/microchip/wilc1000/sdio.c
drivers/net/wireless/microchip/wilc1000/wlan.c
drivers/net/wireless/microchip/wilc1000/wlan.h
drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
drivers/net/wireless/realtek/rtw88/coex.c
drivers/net/wireless/realtek/rtw88/coex.h
drivers/net/wireless/realtek/rtw88/debug.c
drivers/net/wireless/realtek/rtw88/hci.h
drivers/net/wireless/realtek/rtw88/mac.c
drivers/net/wireless/realtek/rtw88/mac.h
drivers/net/wireless/realtek/rtw88/mac80211.c
drivers/net/wireless/realtek/rtw88/main.c
drivers/net/wireless/realtek/rtw88/main.h
drivers/net/wireless/realtek/rtw88/pci.c
drivers/net/wireless/realtek/rtw88/phy.c
drivers/net/wireless/realtek/rtw88/phy.h
drivers/net/wireless/realtek/rtw88/reg.h
drivers/net/wireless/realtek/rtw88/rtw8822c.c
drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
drivers/net/wireless/rsi/rsi_91x_ps.c
drivers/nfc/st-nci/spi.c
drivers/of/of_net.c
drivers/staging/octeon/ethernet.c
drivers/staging/wfx/main.c
include/linux/of_net.h
include/linux/stmmac.h
include/net/dsa.h
net/core/skbuff.c
net/dsa/dsa2.c
net/dsa/slave.c
net/ethernet/eth.c
net/ipv4/esp4.c
net/ipv4/icmp.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/ipv6/esp6_offload.c
net/ipv6/icmp.c

index 6a59563..90ac4fe 100644 (file)
@@ -19,7 +19,8 @@ Required properties:
              "renesas,can-r8a7793" if CAN controller is a part of R8A7793 SoC.
              "renesas,can-r8a7794" if CAN controller is a part of R8A7794 SoC.
              "renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC.
-             "renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC.
+             "renesas,can-r8a7796" if CAN controller is a part of R8A77960 SoC.
+             "renesas,can-r8a77961" if CAN controller is a part of R8A77961 SoC.
              "renesas,can-r8a77965" if CAN controller is a part of R8A77965 SoC.
              "renesas,can-r8a77990" if CAN controller is a part of R8A77990 SoC.
              "renesas,can-r8a77995" if CAN controller is a part of R8A77995 SoC.
@@ -40,7 +41,7 @@ Required properties:
 - pinctrl-names: must be "default".
 
 Required properties for R8A774A1, R8A774B1, R8A774C0, R8A774E1, R8A7795,
-R8A7796, R8A77965, R8A77990, and R8A77995:
+R8A77960, R8A77961, R8A77965, R8A77990, and R8A77995:
 For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can
 be used by both CAN and CAN FD controller at the same time. It needs to be
 scaled to maximum frequency if any of these controllers use it. This is done
index 2645a02..da5212e 100644 (file)
@@ -43,11 +43,12 @@ description:
 
 properties:
   compatible:
-    oneOf:
-      - const: "qcom,sc7180-ipa"
-      - const: "qcom,sc7280-ipa"
-      - const: "qcom,sdm845-ipa"
-      - const: "qcom,sdx55-ipa"
+    enum:
+      - qcom,sc7180-ipa
+      - qcom,sc7280-ipa
+      - qcom,sdm845-ipa
+      - qcom,sdx55-ipa
+      - qcom,sm8350-ipa
 
   reg:
     items:
index ceaad6d..06b1706 100644 (file)
@@ -84,6 +84,7 @@ static void __init kirkwood_dt_eth_fixup(void)
                struct device_node *pnp = of_get_parent(np);
                struct clk *clk;
                struct property *pmac;
+               u8 tmpmac[ETH_ALEN];
                void __iomem *io;
                u8 *macaddr;
                u32 reg;
@@ -93,7 +94,7 @@ static void __init kirkwood_dt_eth_fixup(void)
 
                /* skip disabled nodes or nodes with valid MAC address*/
                if (!of_device_is_available(pnp) ||
-                   !IS_ERR(of_get_mac_address(np)))
+                   !of_get_mac_address(np, tmpmac))
                        goto eth_fixup_skip;
 
                clk = of_clk_get(pnp, 0);
index 0baec82..4c4a6ef 100644 (file)
@@ -73,7 +73,6 @@ static int __init tsi108_eth_of_init(void)
                struct device_node *phy, *mdio;
                hw_info tsi_eth_data;
                const unsigned int *phy_id;
-               const void *mac_addr;
                const phandle *ph;
 
                memset(r, 0, sizeof(r));
@@ -101,9 +100,7 @@ static int __init tsi108_eth_of_init(void)
                        goto err;
                }
 
-               mac_addr = of_get_mac_address(np);
-               if (!IS_ERR(mac_addr))
-                       ether_addr_copy(tsi_eth_data.mac_addr, mac_addr);
+               of_get_mac_address(np, tsi_eth_data.mac_addr);
 
                ph = of_get_property(np, "mdio-handle", NULL);
                mdio = of_find_node_by_phandle(*ph);
index 0c13cac..9e4bd75 100644 (file)
@@ -1783,12 +1783,6 @@ set_tct(struct idt77252_dev *card, struct vc_map *vc)
 /*                                                                           */
 /*****************************************************************************/
 
-static __inline__ int
-idt77252_fbq_level(struct idt77252_dev *card, int queue)
-{
-       return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) & 0x0f;
-}
-
 static __inline__ int
 idt77252_fbq_full(struct idt77252_dev *card, int queue)
 {
index 890c86e..df79e73 100644 (file)
@@ -59,9 +59,6 @@ static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe)
  * look for EISA/PCI cards in addition to ISA cards).
  */
 static struct devprobe2 isa_probes[] __initdata = {
-#if defined(CONFIG_HP100) && defined(CONFIG_ISA)       /* ISA, EISA */
-       {hp100_probe, 0},
-#endif
 #ifdef CONFIG_3C515
        {tc515_probe, 0},
 #endif
index 538f4d9..3deb9f1 100644 (file)
@@ -20,6 +20,16 @@ config CAN_ESD_USB2
          This driver supports the CAN-USB/2 interface
          from esd electronic system design gmbh (http://www.esd.eu).
 
+config CAN_ETAS_ES58X
+       tristate "ETAS ES58X CAN/USB interfaces"
+       select CRC16
+       help
+         This driver supports the ES581.4, ES582.1 and ES584.1 interfaces
+         from ETAS GmbH (https://www.etas.com/en/products/es58x.php).
+
+         To compile this driver as a module, choose M here: the module
+         will be called etas_es58x.
+
 config CAN_GS_USB
        tristate "Geschwister Schneider UG interfaces"
        help
index aa0f17c..748cf31 100644 (file)
@@ -6,6 +6,7 @@
 obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
 obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
 obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
+obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x/
 obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb/
 obj-$(CONFIG_CAN_MCBA_USB) += mcba_usb.o
diff --git a/drivers/net/can/usb/etas_es58x/Makefile b/drivers/net/can/usb/etas_es58x/Makefile
new file mode 100644 (file)
index 0000000..a129b4a
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x.o
+etas_es58x-y = es58x_core.o es581_4.o es58x_fd.o
diff --git a/drivers/net/can/usb/etas_es58x/es581_4.c b/drivers/net/can/usb/etas_es58x/es581_4.c
new file mode 100644 (file)
index 0000000..1985f77
--- /dev/null
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
+ *
+ * File es581_4.c: Adds support to ETAS ES581.4.
+ *
+ * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
+ * Copyright (c) 2020 ETAS K.K.. All rights reserved.
+ * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
+ */
+
+#include <linux/kernel.h>
+#include <asm/unaligned.h>
+
+#include "es58x_core.h"
+#include "es581_4.h"
+
+/**
+ * es581_4_sizeof_rx_tx_msg() - Calculate the actual length of the
+ *     structure of a rx or tx message.
+ * @msg: message of variable length, must have a dlc field.
+ *
+ * Even if RTR frames have actually no payload, the ES58X devices
+ * still expect it. Must be a macro in order to accept several types
+ * (struct es581_4_tx_can_msg and struct es581_4_rx_can_msg) as an
+ * input.
+ *
+ * Return: length of the message.
+ */
+#define es581_4_sizeof_rx_tx_msg(msg)                          \
+       offsetof(typeof(msg), data[can_cc_dlc2len((msg).dlc)])
+
+static u16 es581_4_get_msg_len(const union es58x_urb_cmd *urb_cmd)
+{
+       return get_unaligned_le16(&urb_cmd->es581_4_urb_cmd.msg_len);
+}
+
+static int es581_4_echo_msg(struct es58x_device *es58x_dev,
+                           const struct es581_4_urb_cmd *es581_4_urb_cmd)
+{
+       struct net_device *netdev;
+       const struct es581_4_bulk_echo_msg *bulk_echo_msg;
+       const struct es581_4_echo_msg *echo_msg;
+       u64 *tstamps = es58x_dev->timestamps;
+       u16 msg_len;
+       u32 first_packet_idx, packet_idx;
+       unsigned int dropped = 0;
+       int i, num_element, ret;
+
+       bulk_echo_msg = &es581_4_urb_cmd->bulk_echo_msg;
+       msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len) -
+           sizeof(bulk_echo_msg->channel_no);
+       num_element = es58x_msg_num_element(es58x_dev->dev,
+                                           bulk_echo_msg->echo_msg, msg_len);
+       if (num_element <= 0)
+               return num_element;
+
+       ret = es58x_get_netdev(es58x_dev, bulk_echo_msg->channel_no,
+                              ES581_4_CHANNEL_IDX_OFFSET, &netdev);
+       if (ret)
+               return ret;
+
+       echo_msg = &bulk_echo_msg->echo_msg[0];
+       first_packet_idx = get_unaligned_le32(&echo_msg->packet_idx);
+       packet_idx = first_packet_idx;
+       for (i = 0; i < num_element; i++) {
+               u32 tmp_idx;
+
+               echo_msg = &bulk_echo_msg->echo_msg[i];
+               tmp_idx = get_unaligned_le32(&echo_msg->packet_idx);
+               if (tmp_idx == packet_idx - 1) {
+                       if (net_ratelimit())
+                               netdev_warn(netdev,
+                                           "Received echo packet idx %u twice\n",
+                                           packet_idx - 1);
+                       dropped++;
+                       continue;
+               }
+               if (tmp_idx != packet_idx) {
+                       netdev_err(netdev, "Echo packet idx jumped from %u to %u\n",
+                                  packet_idx - 1, echo_msg->packet_idx);
+                       return -EBADMSG;
+               }
+
+               tstamps[i] = get_unaligned_le64(&echo_msg->timestamp);
+               packet_idx++;
+       }
+
+       netdev->stats.tx_dropped += dropped;
+       return es58x_can_get_echo_skb(netdev, first_packet_idx,
+                                     tstamps, num_element - dropped);
+}
+
+static int es581_4_rx_can_msg(struct es58x_device *es58x_dev,
+                             const struct es581_4_urb_cmd *es581_4_urb_cmd,
+                             u16 msg_len)
+{
+       const struct device *dev = es58x_dev->dev;
+       struct net_device *netdev;
+       int pkts, num_element, channel_no, ret;
+
+       num_element = es58x_msg_num_element(dev, es581_4_urb_cmd->rx_can_msg,
+                                           msg_len);
+       if (num_element <= 0)
+               return num_element;
+
+       channel_no = es581_4_urb_cmd->rx_can_msg[0].channel_no;
+       ret = es58x_get_netdev(es58x_dev, channel_no,
+                              ES581_4_CHANNEL_IDX_OFFSET, &netdev);
+       if (ret)
+               return ret;
+
+       if (!netif_running(netdev)) {
+               if (net_ratelimit())
+                       netdev_info(netdev,
+                                   "%s: %s is down, dropping %d rx packets\n",
+                                   __func__, netdev->name, num_element);
+               netdev->stats.rx_dropped += num_element;
+               return 0;
+       }
+
+       for (pkts = 0; pkts < num_element; pkts++) {
+               const struct es581_4_rx_can_msg *rx_can_msg =
+                   &es581_4_urb_cmd->rx_can_msg[pkts];
+               u64 tstamp = get_unaligned_le64(&rx_can_msg->timestamp);
+               canid_t can_id = get_unaligned_le32(&rx_can_msg->can_id);
+
+               if (channel_no != rx_can_msg->channel_no)
+                       return -EBADMSG;
+
+               ret = es58x_rx_can_msg(netdev, tstamp, rx_can_msg->data,
+                                      can_id, rx_can_msg->flags,
+                                      rx_can_msg->dlc);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int es581_4_rx_err_msg(struct es58x_device *es58x_dev,
+                             const struct es581_4_rx_err_msg *rx_err_msg)
+{
+       struct net_device *netdev;
+       enum es58x_err error = get_unaligned_le32(&rx_err_msg->error);
+       int ret;
+
+       ret = es58x_get_netdev(es58x_dev, rx_err_msg->channel_no,
+                              ES581_4_CHANNEL_IDX_OFFSET, &netdev);
+       if (ret)
+               return ret;
+
+       return es58x_rx_err_msg(netdev, error, 0,
+                               get_unaligned_le64(&rx_err_msg->timestamp));
+}
+
+static int es581_4_rx_event_msg(struct es58x_device *es58x_dev,
+                               const struct es581_4_rx_event_msg *rx_event_msg)
+{
+       struct net_device *netdev;
+       enum es58x_event event = get_unaligned_le32(&rx_event_msg->event);
+       int ret;
+
+       ret = es58x_get_netdev(es58x_dev, rx_event_msg->channel_no,
+                              ES581_4_CHANNEL_IDX_OFFSET, &netdev);
+       if (ret)
+               return ret;
+
+       return es58x_rx_err_msg(netdev, 0, event,
+                               get_unaligned_le64(&rx_event_msg->timestamp));
+}
+
+static int es581_4_rx_cmd_ret_u32(struct es58x_device *es58x_dev,
+                                 const struct es581_4_urb_cmd *es581_4_urb_cmd,
+                                 enum es58x_ret_type ret_type)
+{
+       struct net_device *netdev;
+       const struct es581_4_rx_cmd_ret *rx_cmd_ret;
+       u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);
+       int ret;
+
+       ret = es58x_check_msg_len(es58x_dev->dev,
+                                 es581_4_urb_cmd->rx_cmd_ret, msg_len);
+       if (ret)
+               return ret;
+
+       rx_cmd_ret = &es581_4_urb_cmd->rx_cmd_ret;
+
+       ret = es58x_get_netdev(es58x_dev, rx_cmd_ret->channel_no,
+                              ES581_4_CHANNEL_IDX_OFFSET, &netdev);
+       if (ret)
+               return ret;
+
+       return es58x_rx_cmd_ret_u32(netdev, ret_type,
+                                   get_unaligned_le32(&rx_cmd_ret->rx_cmd_ret_le32));
+}
+
+static int es581_4_tx_ack_msg(struct es58x_device *es58x_dev,
+                             const struct es581_4_urb_cmd *es581_4_urb_cmd)
+{
+       struct net_device *netdev;
+       const struct es581_4_tx_ack_msg *tx_ack_msg;
+       u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);
+       int ret;
+
+       tx_ack_msg = &es581_4_urb_cmd->tx_ack_msg;
+       ret = es58x_check_msg_len(es58x_dev->dev, *tx_ack_msg, msg_len);
+       if (ret)
+               return ret;
+
+       if (tx_ack_msg->rx_cmd_ret_u8 != ES58X_RET_U8_OK)
+               return es58x_rx_cmd_ret_u8(es58x_dev->dev,
+                                          ES58X_RET_TYPE_TX_MSG,
+                                          tx_ack_msg->rx_cmd_ret_u8);
+
+       ret = es58x_get_netdev(es58x_dev, tx_ack_msg->channel_no,
+                              ES581_4_CHANNEL_IDX_OFFSET, &netdev);
+       if (ret)
+               return ret;
+
+       return es58x_tx_ack_msg(netdev,
+                               get_unaligned_le16(&tx_ack_msg->tx_free_entries),
+                               ES58X_RET_U32_OK);
+}
+
+static int es581_4_dispatch_rx_cmd(struct es58x_device *es58x_dev,
+                                  const struct es581_4_urb_cmd *es581_4_urb_cmd)
+{
+       const struct device *dev = es58x_dev->dev;
+       u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);
+       enum es581_4_rx_type rx_type = es581_4_urb_cmd->rx_can_msg[0].rx_type;
+       int ret = 0;
+
+       switch (rx_type) {
+       case ES581_4_RX_TYPE_MESSAGE:
+               return es581_4_rx_can_msg(es58x_dev, es581_4_urb_cmd, msg_len);
+
+       case ES581_4_RX_TYPE_ERROR:
+               ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_err_msg,
+                                         msg_len);
+               if (ret < 0)
+                       return ret;
+               return es581_4_rx_err_msg(es58x_dev,
+                                         &es581_4_urb_cmd->rx_err_msg);
+
+       case ES581_4_RX_TYPE_EVENT:
+               ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_event_msg,
+                                         msg_len);
+               if (ret < 0)
+                       return ret;
+               return es581_4_rx_event_msg(es58x_dev,
+                                           &es581_4_urb_cmd->rx_event_msg);
+
+       default:
+               dev_err(dev, "%s: Unknown rx_type 0x%02X\n", __func__, rx_type);
+               return -EBADRQC;
+       }
+}
+
+static int es581_4_handle_urb_cmd(struct es58x_device *es58x_dev,
+                                 const union es58x_urb_cmd *urb_cmd)
+{
+       const struct es581_4_urb_cmd *es581_4_urb_cmd;
+       struct device *dev = es58x_dev->dev;
+       u16 msg_len = es581_4_get_msg_len(urb_cmd);
+       int ret;
+
+       es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;
+
+       if (es581_4_urb_cmd->cmd_type != ES581_4_CAN_COMMAND_TYPE) {
+               dev_err(dev, "%s: Unknown command type (0x%02X)\n",
+                       __func__, es581_4_urb_cmd->cmd_type);
+               return -EBADRQC;
+       }
+
+       switch ((enum es581_4_cmd_id)es581_4_urb_cmd->cmd_id) {
+       case ES581_4_CMD_ID_SET_BITTIMING:
+               return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
+                                             ES58X_RET_TYPE_SET_BITTIMING);
+
+       case ES581_4_CMD_ID_ENABLE_CHANNEL:
+               return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
+                                             ES58X_RET_TYPE_ENABLE_CHANNEL);
+
+       case ES581_4_CMD_ID_TX_MSG:
+               return es581_4_tx_ack_msg(es58x_dev, es581_4_urb_cmd);
+
+       case ES581_4_CMD_ID_RX_MSG:
+               return es581_4_dispatch_rx_cmd(es58x_dev, es581_4_urb_cmd);
+
+       case ES581_4_CMD_ID_RESET_RX:
+               ret = es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
+                                            ES58X_RET_TYPE_RESET_RX);
+               return ret;
+
+       case ES581_4_CMD_ID_RESET_TX:
+               ret = es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
+                                            ES58X_RET_TYPE_RESET_TX);
+               return ret;
+
+       case ES581_4_CMD_ID_DISABLE_CHANNEL:
+               return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
+                                             ES58X_RET_TYPE_DISABLE_CHANNEL);
+
+       case ES581_4_CMD_ID_TIMESTAMP:
+               ret = es58x_check_msg_len(dev, es581_4_urb_cmd->timestamp,
+                                         msg_len);
+               if (ret < 0)
+                       return ret;
+               es58x_rx_timestamp(es58x_dev,
+                                  get_unaligned_le64(&es581_4_urb_cmd->timestamp));
+               return 0;
+
+       case ES581_4_CMD_ID_ECHO:
+               return es581_4_echo_msg(es58x_dev, es581_4_urb_cmd);
+
+       case ES581_4_CMD_ID_DEVICE_ERR:
+               ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_cmd_ret_u8,
+                                         msg_len);
+               if (ret)
+                       return ret;
+               return es58x_rx_cmd_ret_u8(dev, ES58X_RET_TYPE_DEVICE_ERR,
+                                          es581_4_urb_cmd->rx_cmd_ret_u8);
+
+       default:
+               dev_warn(dev, "%s: Unexpected command ID: 0x%02X\n",
+                        __func__, es581_4_urb_cmd->cmd_id);
+               return -EBADRQC;
+       }
+}
+
+static void es581_4_fill_urb_header(union es58x_urb_cmd *urb_cmd, u8 cmd_type,
+                                   u8 cmd_id, u8 channel_idx, u16 msg_len)
+{
+       struct es581_4_urb_cmd *es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;
+
+       es581_4_urb_cmd->SOF = cpu_to_le16(es581_4_param.tx_start_of_frame);
+       es581_4_urb_cmd->cmd_type = cmd_type;
+       es581_4_urb_cmd->cmd_id = cmd_id;
+       es581_4_urb_cmd->msg_len = cpu_to_le16(msg_len);
+}
+
+static int es581_4_tx_can_msg(struct es58x_priv *priv,
+                             const struct sk_buff *skb)
+{
+       struct es58x_device *es58x_dev = priv->es58x_dev;
+       union es58x_urb_cmd *urb_cmd = priv->tx_urb->transfer_buffer;
+       struct es581_4_urb_cmd *es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;
+       struct can_frame *cf = (struct can_frame *)skb->data;
+       struct es581_4_tx_can_msg *tx_can_msg;
+       u16 msg_len;
+       int ret;
+
+       if (can_is_canfd_skb(skb))
+               return -EMSGSIZE;
+
+       if (priv->tx_can_msg_cnt == 0) {
+               msg_len = 1; /* struct es581_4_bulk_tx_can_msg:num_can_msg */
+               es581_4_fill_urb_header(urb_cmd, ES581_4_CAN_COMMAND_TYPE,
+                                       ES581_4_CMD_ID_TX_MSG,
+                                       priv->channel_idx, msg_len);
+               es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg = 0;
+       } else {
+               msg_len = es581_4_get_msg_len(urb_cmd);
+       }
+
+       ret = es58x_check_msg_max_len(es58x_dev->dev,
+                                     es581_4_urb_cmd->bulk_tx_can_msg,
+                                     msg_len + sizeof(*tx_can_msg));
+       if (ret)
+               return ret;
+
+       /* Fill message contents. */
+       tx_can_msg = (struct es581_4_tx_can_msg *)
+           &es581_4_urb_cmd->bulk_tx_can_msg.tx_can_msg_buf[msg_len - 1];
+       put_unaligned_le32(es58x_get_raw_can_id(cf), &tx_can_msg->can_id);
+       put_unaligned_le32(priv->tx_head, &tx_can_msg->packet_idx);
+       put_unaligned_le16((u16)es58x_get_flags(skb), &tx_can_msg->flags);
+       tx_can_msg->channel_no = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;
+       tx_can_msg->dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
+
+       memcpy(tx_can_msg->data, cf->data, cf->len);
+
+       /* Calculate new sizes. */
+       es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg++;
+       msg_len += es581_4_sizeof_rx_tx_msg(*tx_can_msg);
+       priv->tx_urb->transfer_buffer_length = es58x_get_urb_cmd_len(es58x_dev,
+                                                                    msg_len);
+       es581_4_urb_cmd->msg_len = cpu_to_le16(msg_len);
+
+       return 0;
+}
+
+static int es581_4_set_bittiming(struct es58x_priv *priv)
+{
+       struct es581_4_tx_conf_msg tx_conf_msg = { 0 };
+       struct can_bittiming *bt = &priv->can.bittiming;
+
+       tx_conf_msg.bitrate = cpu_to_le32(bt->bitrate);
+       /* bt->sample_point is in tenth of percent. Convert it to percent. */
+       tx_conf_msg.sample_point = cpu_to_le32(bt->sample_point / 10U);
+       tx_conf_msg.samples_per_bit = cpu_to_le32(ES58X_SAMPLES_PER_BIT_ONE);
+       tx_conf_msg.bit_time = cpu_to_le32(can_bit_time(bt));
+       tx_conf_msg.sjw = cpu_to_le32(bt->sjw);
+       tx_conf_msg.sync_edge = cpu_to_le32(ES58X_SYNC_EDGE_SINGLE);
+       tx_conf_msg.physical_layer =
+           cpu_to_le32(ES58X_PHYSICAL_LAYER_HIGH_SPEED);
+       tx_conf_msg.echo_mode = cpu_to_le32(ES58X_ECHO_ON);
+       tx_conf_msg.channel_no = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;
+
+       return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,
+                             ES581_4_CMD_ID_SET_BITTIMING, &tx_conf_msg,
+                             sizeof(tx_conf_msg), priv->channel_idx);
+}
+
+static int es581_4_enable_channel(struct es58x_priv *priv)
+{
+       int ret;
+       u8 msg = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;
+
+       ret = es581_4_set_bittiming(priv);
+       if (ret)
+               return ret;
+
+       return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,
+                             ES581_4_CMD_ID_ENABLE_CHANNEL, &msg, sizeof(msg),
+                             priv->channel_idx);
+}
+
+static int es581_4_disable_channel(struct es58x_priv *priv)
+{
+       u8 msg = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;
+
+       return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,
+                             ES581_4_CMD_ID_DISABLE_CHANNEL, &msg, sizeof(msg),
+                             priv->channel_idx);
+}
+
+static int es581_4_reset_device(struct es58x_device *es58x_dev)
+{
+       return es58x_send_msg(es58x_dev, ES581_4_CAN_COMMAND_TYPE,
+                             ES581_4_CMD_ID_RESET_DEVICE,
+                             ES58X_EMPTY_MSG, 0, ES58X_CHANNEL_IDX_NA);
+}
+
+static int es581_4_get_timestamp(struct es58x_device *es58x_dev)
+{
+       return es58x_send_msg(es58x_dev, ES581_4_CAN_COMMAND_TYPE,
+                             ES581_4_CMD_ID_TIMESTAMP,
+                             ES58X_EMPTY_MSG, 0, ES58X_CHANNEL_IDX_NA);
+}
+
+/* Nominal bittiming constants for ES581.4 as specified in the
+ * microcontroller datasheet: "Stellaris(R) LM3S5B91 Microcontroller"
+ * table 17-4 "CAN Protocol Ranges" from Texas Instruments.
+ */
+static const struct can_bittiming_const es581_4_bittiming_const = {
+       .name = "ES581.4",
+       .tseg1_min = 1,
+       .tseg1_max = 8,
+       .tseg2_min = 1,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 128,
+       .brp_inc = 1
+};
+
+const struct es58x_parameters es581_4_param = {
+       .bittiming_const = &es581_4_bittiming_const,
+       .data_bittiming_const = NULL,
+       .tdc_const = NULL,
+       .bitrate_max = 1 * CAN_MBPS,
+       .clock = {.freq = 50 * CAN_MHZ},
+       .ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC,
+       .tx_start_of_frame = 0xAFAF,
+       .rx_start_of_frame = 0xFAFA,
+       .tx_urb_cmd_max_len = ES581_4_TX_URB_CMD_MAX_LEN,
+       .rx_urb_cmd_max_len = ES581_4_RX_URB_CMD_MAX_LEN,
+       /* Size of internal device TX queue is 330.
+        *
+        * However, we witnessed some ES58X_ERR_PROT_CRC errors from
+        * the device and thus, echo_skb_max was lowered to the
+        * empirical value of 75 which seems stable and then rounded
+        * down to become a power of two.
+        *
+        * Root cause of those ES58X_ERR_PROT_CRC errors is still
+        * unclear.
+        */
+       .fifo_mask = 63, /* echo_skb_max = 64 */
+       .dql_min_limit = CAN_FRAME_LEN_MAX * 50, /* Empirical value. */
+       .tx_bulk_max = ES581_4_TX_BULK_MAX,
+       .urb_cmd_header_len = ES581_4_URB_CMD_HEADER_LEN,
+       .rx_urb_max = ES58X_RX_URBS_MAX,
+       .tx_urb_max = ES58X_TX_URBS_MAX
+};
+
+const struct es58x_operators es581_4_ops = {
+       .get_msg_len = es581_4_get_msg_len,
+       .handle_urb_cmd = es581_4_handle_urb_cmd,
+       .fill_urb_header = es581_4_fill_urb_header,
+       .tx_can_msg = es581_4_tx_can_msg,
+       .enable_channel = es581_4_enable_channel,
+       .disable_channel = es581_4_disable_channel,
+       .reset_device = es581_4_reset_device,
+       .get_timestamp = es581_4_get_timestamp
+};
diff --git a/drivers/net/can/usb/etas_es58x/es581_4.h b/drivers/net/can/usb/etas_es58x/es581_4.h
new file mode 100644 (file)
index 0000000..4bc60a6
--- /dev/null
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
+ *
+ * File es581_4.h: Definitions and declarations specific to ETAS
+ * ES581.4.
+ *
+ * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
+ * Copyright (c) 2020 ETAS K.K.. All rights reserved.
+ * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
+ */
+
+#ifndef __ES581_4_H__
+#define __ES581_4_H__
+
+#include <linux/types.h>
+
+#define ES581_4_NUM_CAN_CH 2
+#define ES581_4_CHANNEL_IDX_OFFSET 1
+
+#define ES581_4_TX_BULK_MAX 25
+#define ES581_4_RX_BULK_MAX 30
+#define ES581_4_ECHO_BULK_MAX 30
+
+enum es581_4_cmd_type {
+       ES581_4_CAN_COMMAND_TYPE = 0x45
+};
+
+enum es581_4_cmd_id {
+       ES581_4_CMD_ID_OPEN_CHANNEL = 0x01,
+       ES581_4_CMD_ID_CLOSE_CHANNEL = 0x02,
+       ES581_4_CMD_ID_SET_BITTIMING = 0x03,
+       ES581_4_CMD_ID_ENABLE_CHANNEL = 0x04,
+       ES581_4_CMD_ID_TX_MSG = 0x05,
+       ES581_4_CMD_ID_RX_MSG = 0x06,
+       ES581_4_CMD_ID_RESET_RX = 0x0A,
+       ES581_4_CMD_ID_RESET_TX = 0x0B,
+       ES581_4_CMD_ID_DISABLE_CHANNEL = 0x0C,
+       ES581_4_CMD_ID_TIMESTAMP = 0x0E,
+       ES581_4_CMD_ID_RESET_DEVICE = 0x28,
+       ES581_4_CMD_ID_ECHO = 0x71,
+       ES581_4_CMD_ID_DEVICE_ERR = 0x72
+};
+
+enum es581_4_rx_type {
+       ES581_4_RX_TYPE_MESSAGE = 1,
+       ES581_4_RX_TYPE_ERROR = 3,
+       ES581_4_RX_TYPE_EVENT = 4
+};
+
+/**
+ * struct es581_4_tx_conf_msg - Channel configuration.
+ * @bitrate: Bitrate.
+ * @sample_point: Sample point is in percent [0..100].
+ * @samples_per_bit: type enum es58x_samples_per_bit.
+ * @bit_time: Number of time quanta in one bit.
+ * @sjw: Synchronization Jump Width.
+ * @sync_edge: type enum es58x_sync_edge.
+ * @physical_layer: type enum es58x_physical_layer.
+ * @echo_mode: type enum es58x_echo_mode.
+ * @channel_no: Channel number, starting from 1. Not to be confused
+ *     with channed_idx of the ES58X FD which starts from 0.
+ */
+struct es581_4_tx_conf_msg {
+       __le32 bitrate;
+       __le32 sample_point;
+       __le32 samples_per_bit;
+       __le32 bit_time;
+       __le32 sjw;
+       __le32 sync_edge;
+       __le32 physical_layer;
+       __le32 echo_mode;
+       u8 channel_no;
+} __packed;
+
+struct es581_4_tx_can_msg {
+       __le32 can_id;
+       __le32 packet_idx;
+       __le16 flags;
+       u8 channel_no;
+       u8 dlc;
+       u8 data[CAN_MAX_DLEN];
+} __packed;
+
+/* The ES581.4 allows bulk transfer.  */
+struct es581_4_bulk_tx_can_msg {
+       u8 num_can_msg;
+       /* Using type "u8[]" instead of "struct es581_4_tx_can_msg[]"
+        * for tx_msg_buf because each member has a flexible size.
+        */
+       u8 tx_can_msg_buf[ES581_4_TX_BULK_MAX *
+                         sizeof(struct es581_4_tx_can_msg)];
+} __packed;
+
+struct es581_4_echo_msg {
+       __le64 timestamp;
+       __le32 packet_idx;
+} __packed;
+
+struct es581_4_bulk_echo_msg {
+       u8 channel_no;
+       struct es581_4_echo_msg echo_msg[ES581_4_ECHO_BULK_MAX];
+} __packed;
+
+/* Normal Rx CAN Message */
+struct es581_4_rx_can_msg {
+       __le64 timestamp;
+       u8 rx_type;             /* type enum es581_4_rx_type */
+       u8 flags;               /* type enum es58x_flag */
+       u8 channel_no;
+       u8 dlc;
+       __le32 can_id;
+       u8 data[CAN_MAX_DLEN];
+} __packed;
+
+struct es581_4_rx_err_msg {
+       __le64 timestamp;
+       __le16 rx_type;         /* type enum es581_4_rx_type */
+       __le16 flags;           /* type enum es58x_flag */
+       u8 channel_no;
+       u8 __padding[2];
+       u8 dlc;
+       __le32 tag;             /* Related to the CAN filtering. Unused in this module */
+       __le32 can_id;
+       __le32 error;           /* type enum es58x_error */
+       __le32 destination;     /* Unused in this module */
+} __packed;
+
+struct es581_4_rx_event_msg {
+       __le64 timestamp;
+       __le16 rx_type;         /* type enum es581_4_rx_type */
+       u8 channel_no;
+       u8 __padding;
+       __le32 tag;             /* Related to the CAN filtering. Unused in this module */
+       __le32 event;           /* type enum es58x_event */
+       __le32 destination;     /* Unused in this module */
+} __packed;
+
+struct es581_4_tx_ack_msg {
+       __le16 tx_free_entries; /* Number of remaining free entries in the device TX queue */
+       u8 channel_no;
+       u8 rx_cmd_ret_u8;       /* type enum es58x_cmd_ret_code_u8 */
+} __packed;
+
+struct es581_4_rx_cmd_ret {
+       __le32 rx_cmd_ret_le32;
+       u8 channel_no;
+       u8 __padding[3];
+} __packed;
+
+/**
+ * struct es581_4_urb_cmd - Commands received from or sent to the
+ *     ES581.4 device.
+ * @SOF: Start of Frame.
+ * @cmd_type: Command Type (type: enum es581_4_cmd_type). The CRC
+ *     calculation starts at this position.
+ * @cmd_id: Command ID (type: enum es581_4_cmd_id).
+ * @msg_len: Length of the message, excluding CRC (i.e. length of the
+ *     union).
+ * @tx_conf_msg: Channel configuration.
+ * @bulk_tx_can_msg: Tx messages.
+ * @rx_can_msg: Array of Rx messages.
+ * @bulk_echo_msg: Tx message being looped back.
+ * @rx_err_msg: Error message.
+ * @rx_event_msg: Event message.
+ * @tx_ack_msg: Tx acknowledgment message.
+ * @rx_cmd_ret: Command return code.
+ * @timestamp: Timestamp reply.
+ * @rx_cmd_ret_u8: Rx 8 bits return code (type: enum
+ *     es58x_cmd_ret_code_u8).
+ * @raw_msg: Message raw payload.
+ * @reserved_for_crc16_do_not_use: The structure ends with a
+ *     CRC16. Because the structures in above union are of variable
+ *     lengths, we can not predict the offset of the CRC in
+ *     advance. Use functions es58x_get_crc() and es58x_set_crc() to
+ *     manipulate it.
+ */
+struct es581_4_urb_cmd {
+       __le16 SOF;
+       u8 cmd_type;
+       u8 cmd_id;
+       __le16 msg_len;
+
+       union {
+               struct es581_4_tx_conf_msg tx_conf_msg;
+               struct es581_4_bulk_tx_can_msg bulk_tx_can_msg;
+               struct es581_4_rx_can_msg rx_can_msg[ES581_4_RX_BULK_MAX];
+               struct es581_4_bulk_echo_msg bulk_echo_msg;
+               struct es581_4_rx_err_msg rx_err_msg;
+               struct es581_4_rx_event_msg rx_event_msg;
+               struct es581_4_tx_ack_msg tx_ack_msg;
+               struct es581_4_rx_cmd_ret rx_cmd_ret;
+               __le64 timestamp;
+               u8 rx_cmd_ret_u8;
+               u8 raw_msg[0];
+       } __packed;
+
+       __le16 reserved_for_crc16_do_not_use;
+} __packed;
+
+#define ES581_4_URB_CMD_HEADER_LEN (offsetof(struct es581_4_urb_cmd, raw_msg))
+#define ES581_4_TX_URB_CMD_MAX_LEN                                     \
+       ES58X_SIZEOF_URB_CMD(struct es581_4_urb_cmd, bulk_tx_can_msg)
+#define ES581_4_RX_URB_CMD_MAX_LEN                                     \
+       ES58X_SIZEOF_URB_CMD(struct es581_4_urb_cmd, rx_can_msg)
+
+#endif /* __ES581_4_H__ */
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
new file mode 100644 (file)
index 0000000..7222b3b
--- /dev/null
@@ -0,0 +1,2301 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
+ *
+ * File es58x_core.c: Core logic to manage the network devices and the
+ * USB interface.
+ *
+ * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
+ * Copyright (c) 2020 ETAS K.K.. All rights reserved.
+ * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/crc16.h>
+#include <asm/unaligned.h>
+
+#include "es58x_core.h"
+
+#define DRV_VERSION "1.00"
+MODULE_AUTHOR("Mailhol Vincent <mailhol.vincent@wanadoo.fr>");
+MODULE_AUTHOR("Arunachalam Santhanam <arunachalam.santhanam@in.bosch.com>");
+MODULE_DESCRIPTION("Socket CAN driver for ETAS ES58X USB adapters");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL v2");
+
+#define ES58X_MODULE_NAME "etas_es58x"
+#define ES58X_VENDOR_ID 0x108C
+#define ES581_4_PRODUCT_ID 0x0159
+#define ES582_1_PRODUCT_ID 0x0168
+#define ES584_1_PRODUCT_ID 0x0169
+
+/* ES58X FD has some interface protocols unsupported by this driver. */
+#define ES58X_FD_INTERFACE_PROTOCOL 0
+
+/* Table of devices which work with this driver. */
+static const struct usb_device_id es58x_id_table[] = {
+       {
+               /* ETAS GmbH ES581.4 USB dual-channel CAN Bus Interface module. */
+               USB_DEVICE(ES58X_VENDOR_ID, ES581_4_PRODUCT_ID),
+               .driver_info = ES58X_DUAL_CHANNEL
+       }, {
+               /* ETAS GmbH ES582.1 USB dual-channel CAN FD Bus Interface module. */
+               USB_DEVICE_INTERFACE_PROTOCOL(ES58X_VENDOR_ID, ES582_1_PRODUCT_ID,
+                                             ES58X_FD_INTERFACE_PROTOCOL),
+               .driver_info = ES58X_DUAL_CHANNEL | ES58X_FD_FAMILY
+       }, {
+               /* ETAS GmbH ES584.1 USB single-channel CAN FD Bus Interface module. */
+               USB_DEVICE_INTERFACE_PROTOCOL(ES58X_VENDOR_ID, ES584_1_PRODUCT_ID,
+                                             ES58X_FD_INTERFACE_PROTOCOL),
+               .driver_info = ES58X_FD_FAMILY
+       }, {
+               /* Terminating entry */
+       }
+};
+
+MODULE_DEVICE_TABLE(usb, es58x_id_table);
+
+#define es58x_print_hex_dump(buf, len)                                 \
+       print_hex_dump(KERN_DEBUG,                                      \
+                      ES58X_MODULE_NAME " " __stringify(buf) ": ",     \
+                      DUMP_PREFIX_NONE, 16, 1, buf, len, false)
+
+#define es58x_print_hex_dump_debug(buf, len)                            \
+       print_hex_dump_debug(ES58X_MODULE_NAME " " __stringify(buf) ": ",\
+                            DUMP_PREFIX_NONE, 16, 1, buf, len, false)
+
+/* The last two bytes of an ES58X command is a CRC16. The first two
+ * bytes (the start of frame) are skipped and the CRC calculation
+ * starts on the third byte.
+ */
+#define ES58X_CRC_CALC_OFFSET 2
+
+/**
+ * es58x_calculate_crc() - Compute the crc16 of a given URB.
+ * @urb_cmd: The URB command for which we want to calculate the CRC.
+ * @urb_len: Length of @urb_cmd. Must be at least bigger than 4
+ *     (ES58X_CRC_CALC_OFFSET + sizeof(crc))
+ *
+ * Return: crc16 value.
+ */
+static u16 es58x_calculate_crc(const union es58x_urb_cmd *urb_cmd, u16 urb_len)
+{
+       u16 crc;
+       ssize_t len = urb_len - ES58X_CRC_CALC_OFFSET - sizeof(crc);
+
+       crc = crc16(0, &urb_cmd->raw_cmd[ES58X_CRC_CALC_OFFSET], len);
+       return crc;
+}
+
+/**
+ * es58x_get_crc() - Get the CRC value of a given URB.
+ * @urb_cmd: The URB command for which we want to get the CRC.
+ * @urb_len: Length of @urb_cmd. Must be at least bigger than 4
+ *     (ES58X_CRC_CALC_OFFSET + sizeof(crc))
+ *
+ * Return: crc16 value.
+ */
+static u16 es58x_get_crc(const union es58x_urb_cmd *urb_cmd, u16 urb_len)
+{
+       u16 crc;
+       const __le16 *crc_addr;
+
+       crc_addr = (__le16 *)&urb_cmd->raw_cmd[urb_len - sizeof(crc)];
+       crc = get_unaligned_le16(crc_addr);
+       return crc;
+}
+
+/**
+ * es58x_set_crc() - Set the CRC value of a given URB.
+ * @urb_cmd: The URB command for which we want to get the CRC.
+ * @urb_len: Length of @urb_cmd. Must be at least bigger than 4
+ *     (ES58X_CRC_CALC_OFFSET + sizeof(crc))
+ */
+static void es58x_set_crc(union es58x_urb_cmd *urb_cmd, u16 urb_len)
+{
+       u16 crc;
+       __le16 *crc_addr;
+
+       crc = es58x_calculate_crc(urb_cmd, urb_len);
+       crc_addr = (__le16 *)&urb_cmd->raw_cmd[urb_len - sizeof(crc)];
+       put_unaligned_le16(crc, crc_addr);
+}
+
+/**
+ * es58x_check_crc() - Validate the CRC value of a given URB.
+ * @es58x_dev: ES58X device.
+ * @urb_cmd: The URB command for which we want to check the CRC.
+ * @urb_len: Length of @urb_cmd. Must be at least bigger than 4
+ *     (ES58X_CRC_CALC_OFFSET + sizeof(crc))
+ *
+ * Return: zero on success, -EBADMSG if the CRC check fails.
+ */
+static int es58x_check_crc(struct es58x_device *es58x_dev,
+                          const union es58x_urb_cmd *urb_cmd, u16 urb_len)
+{
+       u16 calculated_crc = es58x_calculate_crc(urb_cmd, urb_len);
+       u16 expected_crc = es58x_get_crc(urb_cmd, urb_len);
+
+       if (expected_crc != calculated_crc) {
+               dev_err_ratelimited(es58x_dev->dev,
+                                   "%s: Bad CRC, urb_len: %d\n",
+                                   __func__, urb_len);
+               return -EBADMSG;
+       }
+
+       return 0;
+}
+
+/**
+ * es58x_timestamp_to_ns() - Convert a timestamp value received from a
+ *     ES58X device to nanoseconds.
+ * @timestamp: Timestamp received from a ES58X device.
+ *
+ * The timestamp received from ES58X is expressed in multiples of 0.5
+ * micro seconds. This function converts it in to nanoseconds.
+ *
+ * Return: Timestamp value in nanoseconds.
+ */
+static u64 es58x_timestamp_to_ns(u64 timestamp)
+{
+       const u64 es58x_timestamp_ns_mult_coef = 500ULL;
+
+       return es58x_timestamp_ns_mult_coef * timestamp;
+}
+
+/**
+ * es58x_set_skb_timestamp() - Set the hardware timestamp of an skb.
+ * @netdev: CAN network device.
+ * @skb: socket buffer of a CAN message.
+ * @timestamp: Timestamp received from an ES58X device.
+ *
+ * Used for both received and echo messages.
+ */
+static void es58x_set_skb_timestamp(struct net_device *netdev,
+                                   struct sk_buff *skb, u64 timestamp)
+{
+       struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
+       struct skb_shared_hwtstamps *hwts;
+
+       hwts = skb_hwtstamps(skb);
+       /* Ignoring overflow (overflow on 64 bits timestamp with nano
+        * second precision would occur after more than 500 years).
+        */
+       hwts->hwtstamp = ns_to_ktime(es58x_timestamp_to_ns(timestamp) +
+                                    es58x_dev->realtime_diff_ns);
+}
+
+/**
+ * es58x_rx_timestamp() - Handle a received timestamp.
+ * @es58x_dev: ES58X device.
+ * @timestamp: Timestamp received from a ES58X device.
+ *
+ * Calculate the difference between the ES58X device and the kernel
+ * internal clocks. This difference will be later used as an offset to
+ * convert the timestamps of RX and echo messages to match the kernel
+ * system time (e.g. convert to UNIX time).
+ */
+void es58x_rx_timestamp(struct es58x_device *es58x_dev, u64 timestamp)
+{
+       u64 ktime_real_ns = ktime_get_real_ns();
+       u64 device_timestamp = es58x_timestamp_to_ns(timestamp);
+
+       dev_dbg(es58x_dev->dev, "%s: request round-trip time: %llu ns\n",
+               __func__, ktime_real_ns - es58x_dev->ktime_req_ns);
+
+       es58x_dev->realtime_diff_ns =
+           (es58x_dev->ktime_req_ns + ktime_real_ns) / 2 - device_timestamp;
+       es58x_dev->ktime_req_ns = 0;
+
+       dev_dbg(es58x_dev->dev,
+               "%s: Device timestamp: %llu, diff with kernel: %llu\n",
+               __func__, device_timestamp, es58x_dev->realtime_diff_ns);
+}
+
+/**
+ * es58x_set_realtime_diff_ns() - Calculate difference between the
+ *     clocks of the ES58X device and the kernel
+ * @es58x_dev: ES58X device.
+ *
+ * Request a timestamp from the ES58X device. Once the answer is
+ * received, the timestamp difference will be set by the callback
+ * function es58x_rx_timestamp().
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_set_realtime_diff_ns(struct es58x_device *es58x_dev)
+{
+       if (es58x_dev->ktime_req_ns) {
+               dev_warn(es58x_dev->dev,
+                        "%s: Previous request to set timestamp has not completed yet\n",
+                        __func__);
+               return -EBUSY;
+       }
+
+       es58x_dev->ktime_req_ns = ktime_get_real_ns();
+       return es58x_dev->ops->get_timestamp(es58x_dev);
+}
+
+/**
+ * es58x_is_can_state_active() - Is the network device in an active
+ *     CAN state?
+ * @netdev: CAN network device.
+ *
+ * The device is considered active if it is able to send or receive
+ * CAN frames, that is to say if it is in any of
+ * CAN_STATE_ERROR_ACTIVE, CAN_STATE_ERROR_WARNING or
+ * CAN_STATE_ERROR_PASSIVE states.
+ *
+ * Caution: when recovering from a bus-off,
+ * net/core/dev.c#can_restart() will call
+ * net/core/dev.c#can_flush_echo_skb() without using any kind of
+ * locks. For this reason, it is critical to guarantee that no TX or
+ * echo operations (i.e. any access to priv->echo_skb[]) can be done
+ * while this function is returning false.
+ *
+ * Return: true if the device is active, else returns false.
+ */
+static bool es58x_is_can_state_active(struct net_device *netdev)
+{
+       return es58x_priv(netdev)->can.state < CAN_STATE_BUS_OFF;
+}
+
+/**
+ * es58x_is_echo_skb_threshold_reached() - Determine the limit of how
+ *     many skb slots can be taken before we should stop the network
+ *     queue.
+ * @priv: ES58X private parameters related to the network device.
+ *
+ * We need to save enough free skb slots in order to be able to do
+ * bulk send. This function can be used to determine when to wake or
+ * stop the network queue in regard to the number of skb slots already
+ * taken if the echo FIFO.
+ *
+ * Return: boolean.
+ */
+static bool es58x_is_echo_skb_threshold_reached(struct es58x_priv *priv)
+{
+       u32 num_echo_skb =  priv->tx_head - priv->tx_tail;
+       u32 threshold = priv->can.echo_skb_max -
+               priv->es58x_dev->param->tx_bulk_max + 1;
+
+       return num_echo_skb >= threshold;
+}
+
+/**
+ * es58x_can_free_echo_skb_tail() - Remove the oldest echo skb of the
+ *     echo FIFO.
+ * @netdev: CAN network device.
+ *
+ * Naming convention: the tail is the beginning of the FIFO, i.e. the
+ * first skb to have entered the FIFO.
+ */
+static void es58x_can_free_echo_skb_tail(struct net_device *netdev)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       u16 fifo_mask = priv->es58x_dev->param->fifo_mask;
+       unsigned int frame_len = 0;
+
+       can_free_echo_skb(netdev, priv->tx_tail & fifo_mask, &frame_len);
+       netdev_completed_queue(netdev, 1, frame_len);
+
+       priv->tx_tail++;
+
+       netdev->stats.tx_dropped++;
+}
+
+/**
+ * es58x_can_get_echo_skb_recovery() - Try to re-sync the echo FIFO.
+ * @netdev: CAN network device.
+ * @rcv_packet_idx: Index
+ *
+ * This function should not be called under normal circumstances. In
+ * the unlikely case that one or several URB packages get dropped by
+ * the device, the index will get out of sync. Try to recover by
+ * dropping the echo skb packets with older indexes.
+ *
+ * Return: zero if recovery was successful, -EINVAL otherwise.
+ */
+static int es58x_can_get_echo_skb_recovery(struct net_device *netdev,
+                                          u32 rcv_packet_idx)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       int ret = 0;
+
+       netdev->stats.tx_errors++;
+
+       if (net_ratelimit())
+               netdev_warn(netdev,
+                           "Bad echo packet index: %u. First index: %u, end index %u, num_echo_skb: %02u/%02u\n",
+                           rcv_packet_idx, priv->tx_tail, priv->tx_head,
+                           priv->tx_head - priv->tx_tail,
+                           priv->can.echo_skb_max);
+
+       if ((s32)(rcv_packet_idx - priv->tx_tail) < 0) {
+               if (net_ratelimit())
+                       netdev_warn(netdev,
+                                   "Received echo index is from the past. Ignoring it\n");
+               ret = -EINVAL;
+       } else if ((s32)(rcv_packet_idx - priv->tx_head) >= 0) {
+               if (net_ratelimit())
+                       netdev_err(netdev,
+                                  "Received echo index is from the future. Ignoring it\n");
+               ret = -EINVAL;
+       } else {
+               if (net_ratelimit())
+                       netdev_warn(netdev,
+                                   "Recovery: dropping %u echo skb from index %u to %u\n",
+                                   rcv_packet_idx - priv->tx_tail,
+                                   priv->tx_tail, rcv_packet_idx - 1);
+               while (priv->tx_tail != rcv_packet_idx) {
+                       if (priv->tx_tail == priv->tx_head)
+                               return -EINVAL;
+                       es58x_can_free_echo_skb_tail(netdev);
+               }
+       }
+       return ret;
+}
+
+/**
+ * es58x_can_get_echo_skb() - Get the skb from the echo FIFO and loop
+ *     it back locally.
+ * @netdev: CAN network device.
+ * @rcv_packet_idx: Index of the first packet received from the device.
+ * @tstamps: Array of hardware timestamps received from a ES58X device.
+ * @pkts: Number of packets (and so, length of @tstamps).
+ *
+ * Callback function for when we receive a self reception
+ * acknowledgment.  Retrieves the skb from the echo FIFO, sets its
+ * hardware timestamp (the actual time it was sent) and loops it back
+ * locally.
+ *
+ * The device has to be active (i.e. network interface UP and not in
+ * bus off state or restarting).
+ *
+ * Packet indexes must be consecutive (i.e. index of first packet is
+ * @rcv_packet_idx, index of second packet is @rcv_packet_idx + 1 and
+ * index of last packet is @rcv_packet_idx + @pkts - 1).
+ *
+ * Return: zero on success.
+ */
+int es58x_can_get_echo_skb(struct net_device *netdev, u32 rcv_packet_idx,
+                          u64 *tstamps, unsigned int pkts)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       unsigned int rx_total_frame_len = 0;
+       unsigned int num_echo_skb = priv->tx_head - priv->tx_tail;
+       int i;
+       u16 fifo_mask = priv->es58x_dev->param->fifo_mask;
+
+       if (!netif_running(netdev)) {
+               if (net_ratelimit())
+                       netdev_info(netdev,
+                                   "%s: %s is down, dropping %d echo packets\n",
+                                   __func__, netdev->name, pkts);
+               netdev->stats.tx_dropped += pkts;
+               return 0;
+       } else if (!es58x_is_can_state_active(netdev)) {
+               if (net_ratelimit())
+                       netdev_dbg(netdev,
+                                  "Bus is off or device is restarting. Ignoring %u echo packets from index %u\n",
+                                  pkts, rcv_packet_idx);
+               /* stats.tx_dropped will be (or was already)
+                * incremented by
+                * drivers/net/can/net/dev.c:can_flush_echo_skb().
+                */
+               return 0;
+       } else if (num_echo_skb == 0) {
+               if (net_ratelimit())
+                       netdev_warn(netdev,
+                                   "Received %u echo packets from index: %u but echo skb queue is empty.\n",
+                                   pkts, rcv_packet_idx);
+               netdev->stats.tx_dropped += pkts;
+               return 0;
+       }
+
+       if (priv->tx_tail != rcv_packet_idx) {
+               if (es58x_can_get_echo_skb_recovery(netdev, rcv_packet_idx) < 0) {
+                       if (net_ratelimit())
+                               netdev_warn(netdev,
+                                           "Could not find echo skb for echo packet index: %u\n",
+                                           rcv_packet_idx);
+                       return 0;
+               }
+       }
+       if (num_echo_skb < pkts) {
+               int pkts_drop = pkts - num_echo_skb;
+
+               if (net_ratelimit())
+                       netdev_err(netdev,
+                                  "Received %u echo packets but have only %d echo skb. Dropping %d echo skb\n",
+                                  pkts, num_echo_skb, pkts_drop);
+               netdev->stats.tx_dropped += pkts_drop;
+               pkts -= pkts_drop;
+       }
+
+       for (i = 0; i < pkts; i++) {
+               unsigned int skb_idx = priv->tx_tail & fifo_mask;
+               struct sk_buff *skb = priv->can.echo_skb[skb_idx];
+               unsigned int frame_len = 0;
+
+               if (skb)
+                       es58x_set_skb_timestamp(netdev, skb, tstamps[i]);
+
+               netdev->stats.tx_bytes += can_get_echo_skb(netdev, skb_idx,
+                                                          &frame_len);
+               rx_total_frame_len += frame_len;
+
+               priv->tx_tail++;
+       }
+
+       netdev_completed_queue(netdev, pkts, rx_total_frame_len);
+       netdev->stats.tx_packets += pkts;
+
+       priv->err_passive_before_rtx_success = 0;
+       if (!es58x_is_echo_skb_threshold_reached(priv))
+               netif_wake_queue(netdev);
+
+       return 0;
+}
+
+/**
+ * es58x_can_reset_echo_fifo() - Reset the echo FIFO.
+ * @netdev: CAN network device.
+ *
+ * The echo_skb array of struct can_priv will be flushed by
+ * drivers/net/can/dev.c:can_flush_echo_skb(). This function resets
+ * the parameters of the struct es58x_priv of our device and reset the
+ * queue (c.f. BQL).
+ */
+static void es58x_can_reset_echo_fifo(struct net_device *netdev)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+
+       priv->tx_tail = 0;
+       priv->tx_head = 0;
+       priv->tx_urb = NULL;
+       priv->err_passive_before_rtx_success = 0;
+       netdev_reset_queue(netdev);
+}
+
+/**
+ * es58x_flush_pending_tx_msg() - Reset the buffer for transmission messages.
+ * @netdev: CAN network device.
+ *
+ * es58x_start_xmit() will queue up to tx_bulk_max messages in
+ * &tx_urb buffer and do a bulk send of all messages in one single URB
+ * (c.f. xmit_more flag). When the device recovers from a bus off
+ * state or when the device stops, the tx_urb buffer might still have
+ * pending messages in it and thus need to be flushed.
+ */
+static void es58x_flush_pending_tx_msg(struct net_device *netdev)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       struct es58x_device *es58x_dev = priv->es58x_dev;
+
+       if (priv->tx_urb) {
+               netdev_warn(netdev, "%s: dropping %d TX messages\n",
+                           __func__, priv->tx_can_msg_cnt);
+               netdev->stats.tx_dropped += priv->tx_can_msg_cnt;
+               while (priv->tx_can_msg_cnt > 0) {
+                       unsigned int frame_len = 0;
+                       u16 fifo_mask = priv->es58x_dev->param->fifo_mask;
+
+                       priv->tx_head--;
+                       priv->tx_can_msg_cnt--;
+                       can_free_echo_skb(netdev, priv->tx_head & fifo_mask,
+                                         &frame_len);
+                       netdev_completed_queue(netdev, 1, frame_len);
+               }
+               usb_anchor_urb(priv->tx_urb, &priv->es58x_dev->tx_urbs_idle);
+               atomic_inc(&es58x_dev->tx_urbs_idle_cnt);
+               usb_free_urb(priv->tx_urb);
+       }
+       priv->tx_urb = NULL;
+}
+
+/**
+ * es58x_tx_ack_msg() - Handle acknowledgment messages.
+ * @netdev: CAN network device.
+ * @tx_free_entries: Number of free entries in the device transmit FIFO.
+ * @rx_cmd_ret_u32: error code as returned by the ES58X device.
+ *
+ * ES58X sends an acknowledgment message after a transmission request
+ * is done. This is mandatory for the ES581.4 but is optional (and
+ * deactivated in this driver) for the ES58X_FD family.
+ *
+ * Under normal circumstances, this function should never throw an
+ * error message.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+int es58x_tx_ack_msg(struct net_device *netdev, u16 tx_free_entries,
+                    enum es58x_ret_u32 rx_cmd_ret_u32)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+
+       if (tx_free_entries <= priv->es58x_dev->param->tx_bulk_max) {
+               if (net_ratelimit())
+                       netdev_err(netdev,
+                                  "Only %d entries left in device queue, num_echo_skb: %d/%d\n",
+                                  tx_free_entries,
+                                  priv->tx_head - priv->tx_tail,
+                                  priv->can.echo_skb_max);
+               netif_stop_queue(netdev);
+       }
+
+       return es58x_rx_cmd_ret_u32(netdev, ES58X_RET_TYPE_TX_MSG,
+                                   rx_cmd_ret_u32);
+}
+
+/**
+ * es58x_rx_can_msg() - Handle a received a CAN message.
+ * @netdev: CAN network device.
+ * @timestamp: Hardware time stamp (only relevant in rx branches).
+ * @data: CAN payload.
+ * @can_id: CAN ID.
+ * @es58x_flags: Please refer to enum es58x_flag.
+ * @dlc: Data Length Code (raw value).
+ *
+ * Fill up a CAN skb and post it.
+ *
+ * This function handles the case where the DLC of a classical CAN
+ * frame is greater than CAN_MAX_DLEN (c.f. the len8_dlc field of
+ * struct can_frame).
+ *
+ * Return: zero on success.
+ */
+int es58x_rx_can_msg(struct net_device *netdev, u64 timestamp, const u8 *data,
+                    canid_t can_id, enum es58x_flag es58x_flags, u8 dlc)
+{
+       struct canfd_frame *cfd;
+       struct can_frame *ccf;
+       struct sk_buff *skb;
+       u8 len;
+       bool is_can_fd = !!(es58x_flags & ES58X_FLAG_FD_DATA);
+
+       if (dlc > CAN_MAX_RAW_DLC) {
+               netdev_err(netdev,
+                          "%s: DLC is %d but maximum should be %d\n",
+                          __func__, dlc, CAN_MAX_RAW_DLC);
+               return -EMSGSIZE;
+       }
+
+       if (is_can_fd) {
+               len = can_fd_dlc2len(dlc);
+               skb = alloc_canfd_skb(netdev, &cfd);
+       } else {
+               len = can_cc_dlc2len(dlc);
+               skb = alloc_can_skb(netdev, &ccf);
+               cfd = (struct canfd_frame *)ccf;
+       }
+       if (!skb) {
+               netdev->stats.rx_dropped++;
+               return 0;
+       }
+
+       cfd->can_id = can_id;
+       if (es58x_flags & ES58X_FLAG_EFF)
+               cfd->can_id |= CAN_EFF_FLAG;
+       if (is_can_fd) {
+               cfd->len = len;
+               if (es58x_flags & ES58X_FLAG_FD_BRS)
+                       cfd->flags |= CANFD_BRS;
+               if (es58x_flags & ES58X_FLAG_FD_ESI)
+                       cfd->flags |= CANFD_ESI;
+       } else {
+               can_frame_set_cc_len(ccf, dlc, es58x_priv(netdev)->can.ctrlmode);
+               if (es58x_flags & ES58X_FLAG_RTR) {
+                       ccf->can_id |= CAN_RTR_FLAG;
+                       len = 0;
+               }
+       }
+       memcpy(cfd->data, data, len);
+       netdev->stats.rx_packets++;
+       netdev->stats.rx_bytes += len;
+
+       es58x_set_skb_timestamp(netdev, skb, timestamp);
+       netif_rx(skb);
+
+       es58x_priv(netdev)->err_passive_before_rtx_success = 0;
+
+       return 0;
+}
+
+/**
+ * es58x_rx_err_msg() - Handle a received CAN event or error message.
+ * @netdev: CAN network device.
+ * @error: Error code.
+ * @event: Event code.
+ * @timestamp: Timestamp received from a ES58X device.
+ *
+ * Handle the errors and events received by the ES58X device, create
+ * a CAN error skb and post it.
+ *
+ * In some rare cases the devices might get stuck alternating between
+ * CAN_STATE_ERROR_PASSIVE and CAN_STATE_ERROR_WARNING. To prevent
+ * this behavior, we force a bus off state if the device goes in
+ * CAN_STATE_ERROR_WARNING for ES58X_MAX_CONSECUTIVE_WARN consecutive
+ * times with no successful transmission or reception in between.
+ *
+ * Once the device is in bus off state, the only way to restart it is
+ * through the drivers/net/can/dev.c:can_restart() function. The
+ * device is technically capable to recover by itself under certain
+ * circumstances, however, allowing self recovery would create
+ * complex race conditions with drivers/net/can/dev.c:can_restart()
+ * and thus was not implemented. To activate automatic restart, please
+ * set the restart-ms parameter (e.g. ip link set can0 type can
+ * restart-ms 100).
+ *
+ * If the bus is really instable, this function would try to send a
+ * lot of log messages. Those are rate limited (i.e. you will see
+ * messages such as "net_ratelimit: XXX callbacks suppressed" in
+ * dmesg).
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
+                    enum es58x_event event, u64 timestamp)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       struct can_priv *can = netdev_priv(netdev);
+       struct can_device_stats *can_stats = &can->can_stats;
+       struct can_frame *cf = NULL;
+       struct sk_buff *skb;
+       int ret;
+
+       if (!netif_running(netdev)) {
+               if (net_ratelimit())
+                       netdev_info(netdev, "%s: %s is down, dropping packet\n",
+                                   __func__, netdev->name);
+               netdev->stats.rx_dropped++;
+               return 0;
+       }
+
+       if (error == ES58X_ERR_OK && event == ES58X_EVENT_OK) {
+               netdev_err(netdev, "%s: Both error and event are zero\n",
+                          __func__);
+               return -EINVAL;
+       }
+
+       skb = alloc_can_err_skb(netdev, &cf);
+
+       switch (error) {
+       case ES58X_ERR_OK:      /* 0: No error */
+               break;
+
+       case ES58X_ERR_PROT_STUFF:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Error BITSUFF\n");
+               if (cf)
+                       cf->data[2] |= CAN_ERR_PROT_STUFF;
+               break;
+
+       case ES58X_ERR_PROT_FORM:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Error FORMAT\n");
+               if (cf)
+                       cf->data[2] |= CAN_ERR_PROT_FORM;
+               break;
+
+       case ES58X_ERR_ACK:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Error ACK\n");
+               if (cf)
+                       cf->can_id |= CAN_ERR_ACK;
+               break;
+
+       case ES58X_ERR_PROT_BIT:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Error BIT\n");
+               if (cf)
+                       cf->data[2] |= CAN_ERR_PROT_BIT;
+               break;
+
+       case ES58X_ERR_PROT_CRC:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Error CRC\n");
+               if (cf)
+                       cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+               break;
+
+       case ES58X_ERR_PROT_BIT1:
+               if (net_ratelimit())
+                       netdev_dbg(netdev,
+                                  "Error: expected a recessive bit but monitored a dominant one\n");
+               if (cf)
+                       cf->data[2] |= CAN_ERR_PROT_BIT1;
+               break;
+
+       case ES58X_ERR_PROT_BIT0:
+               if (net_ratelimit())
+                       netdev_dbg(netdev,
+                                  "Error expected a dominant bit but monitored a recessive one\n");
+               if (cf)
+                       cf->data[2] |= CAN_ERR_PROT_BIT0;
+               break;
+
+       case ES58X_ERR_PROT_OVERLOAD:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Error OVERLOAD\n");
+               if (cf)
+                       cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
+               break;
+
+       case ES58X_ERR_PROT_UNSPEC:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Unspecified error\n");
+               if (cf)
+                       cf->can_id |= CAN_ERR_PROT;
+               break;
+
+       default:
+               if (net_ratelimit())
+                       netdev_err(netdev,
+                                  "%s: Unspecified error code 0x%04X\n",
+                                  __func__, (int)error);
+               if (cf)
+                       cf->can_id |= CAN_ERR_PROT;
+               break;
+       }
+
+       switch (event) {
+       case ES58X_EVENT_OK:    /* 0: No event */
+               break;
+
+       case ES58X_EVENT_CRTL_ACTIVE:
+               if (can->state == CAN_STATE_BUS_OFF) {
+                       netdev_err(netdev,
+                                  "%s: state transition: BUS OFF -> ACTIVE\n",
+                                  __func__);
+               }
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Event CAN BUS ACTIVE\n");
+               if (cf)
+                       cf->data[1] |= CAN_ERR_CRTL_ACTIVE;
+               can->state = CAN_STATE_ERROR_ACTIVE;
+               break;
+
+       case ES58X_EVENT_CRTL_PASSIVE:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Event CAN BUS PASSIVE\n");
+               /* Either TX or RX error count reached passive state
+                * but we do not know which. Setting both flags by
+                * default.
+                */
+               if (cf) {
+                       cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+                       cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+               }
+               if (can->state < CAN_STATE_BUS_OFF)
+                       can->state = CAN_STATE_ERROR_PASSIVE;
+               can_stats->error_passive++;
+               if (priv->err_passive_before_rtx_success < U8_MAX)
+                       priv->err_passive_before_rtx_success++;
+               break;
+
+       case ES58X_EVENT_CRTL_WARNING:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Event CAN BUS WARNING\n");
+               /* Either TX or RX error count reached warning state
+                * but we do not know which. Setting both flags by
+                * default.
+                */
+               if (cf) {
+                       cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+                       cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
+               }
+               if (can->state < CAN_STATE_BUS_OFF)
+                       can->state = CAN_STATE_ERROR_WARNING;
+               can_stats->error_warning++;
+               break;
+
+       case ES58X_EVENT_BUSOFF:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "Event CAN BUS OFF\n");
+               if (cf)
+                       cf->can_id |= CAN_ERR_BUSOFF;
+               can_stats->bus_off++;
+               netif_stop_queue(netdev);
+               if (can->state != CAN_STATE_BUS_OFF) {
+                       can->state = CAN_STATE_BUS_OFF;
+                       can_bus_off(netdev);
+                       ret = can->do_set_mode(netdev, CAN_MODE_STOP);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case ES58X_EVENT_SINGLE_WIRE:
+               if (net_ratelimit())
+                       netdev_warn(netdev,
+                                   "Lost connection on either CAN high or CAN low\n");
+               /* Lost connection on either CAN high or CAN
+                * low. Setting both flags by default.
+                */
+               if (cf) {
+                       cf->data[4] |= CAN_ERR_TRX_CANH_NO_WIRE;
+                       cf->data[4] |= CAN_ERR_TRX_CANL_NO_WIRE;
+               }
+               break;
+
+       default:
+               if (net_ratelimit())
+                       netdev_err(netdev,
+                                  "%s: Unspecified event code 0x%04X\n",
+                                  __func__, (int)event);
+               if (cf)
+                       cf->can_id |= CAN_ERR_CRTL;
+               break;
+       }
+
+       /* driver/net/can/dev.c:can_restart() takes in account error
+        * messages in the RX stats. Doing the same here for
+        * consistency.
+        */
+       netdev->stats.rx_packets++;
+       netdev->stats.rx_bytes += cf->can_dlc;
+
+       if (cf) {
+               if (cf->data[1])
+                       cf->can_id |= CAN_ERR_CRTL;
+               if (cf->data[2] || cf->data[3]) {
+                       cf->can_id |= CAN_ERR_PROT;
+                       can_stats->bus_error++;
+               }
+               if (cf->data[4])
+                       cf->can_id |= CAN_ERR_TRX;
+
+               es58x_set_skb_timestamp(netdev, skb, timestamp);
+               netif_rx(skb);
+       }
+
+       if ((event & ES58X_EVENT_CRTL_PASSIVE) &&
+           priv->err_passive_before_rtx_success == ES58X_CONSECUTIVE_ERR_PASSIVE_MAX) {
+               netdev_info(netdev,
+                           "Got %d consecutive warning events with no successful RX or TX. Forcing bus-off\n",
+                           priv->err_passive_before_rtx_success);
+               return es58x_rx_err_msg(netdev, ES58X_ERR_OK,
+                                       ES58X_EVENT_BUSOFF, timestamp);
+       }
+
+       return 0;
+}
+
+/**
+ * es58x_cmd_ret_desc() - Convert a command type to a string.
+ * @cmd_ret_type: Type of the command which triggered the return code.
+ *
+ * The final line (return "<unknown>") should not be reached. If this
+ * is the case, there is an implementation bug.
+ *
+ * Return: a readable description of the @cmd_ret_type.
+ */
+static const char *es58x_cmd_ret_desc(enum es58x_ret_type cmd_ret_type)
+{
+       switch (cmd_ret_type) {
+       case ES58X_RET_TYPE_SET_BITTIMING:
+               return "Set bittiming";
+       case ES58X_RET_TYPE_ENABLE_CHANNEL:
+               return "Enable channel";
+       case ES58X_RET_TYPE_DISABLE_CHANNEL:
+               return "Disable channel";
+       case ES58X_RET_TYPE_TX_MSG:
+               return "Transmit message";
+       case ES58X_RET_TYPE_RESET_RX:
+               return "Reset RX";
+       case ES58X_RET_TYPE_RESET_TX:
+               return "Reset TX";
+       case ES58X_RET_TYPE_DEVICE_ERR:
+               return "Device error";
+       }
+
+       return "<unknown>";
+};
+
+/**
+ * es58x_rx_cmd_ret_u8() - Handle the command's return code received
+ *     from the ES58X device.
+ * @dev: Device, only used for the dev_XXX() print functions.
+ * @cmd_ret_type: Type of the command which triggered the return code.
+ * @rx_cmd_ret_u8: Command error code as returned by the ES58X device.
+ *
+ * Handles the 8 bits command return code. Those are specific to the
+ * ES581.4 device. The return value will eventually be used by
+ * es58x_handle_urb_cmd() function which will take proper actions in
+ * case of critical issues such and memory errors or bad CRC values.
+ *
+ * In contrast with es58x_rx_cmd_ret_u32(), the network device is
+ * unknown.
+ *
+ * Return: zero on success, return errno when any error occurs.
+ */
+int es58x_rx_cmd_ret_u8(struct device *dev,
+                       enum es58x_ret_type cmd_ret_type,
+                       enum es58x_ret_u8 rx_cmd_ret_u8)
+{
+       const char *ret_desc = es58x_cmd_ret_desc(cmd_ret_type);
+
+       switch (rx_cmd_ret_u8) {
+       case ES58X_RET_U8_OK:
+               dev_dbg_ratelimited(dev, "%s: OK\n", ret_desc);
+               return 0;
+
+       case ES58X_RET_U8_ERR_UNSPECIFIED_FAILURE:
+               dev_err(dev, "%s: unspecified failure\n", ret_desc);
+               return -EBADMSG;
+
+       case ES58X_RET_U8_ERR_NO_MEM:
+               dev_err(dev, "%s: device ran out of memory\n", ret_desc);
+               return -ENOMEM;
+
+       case ES58X_RET_U8_ERR_BAD_CRC:
+               dev_err(dev, "%s: CRC of previous command is incorrect\n",
+                       ret_desc);
+               return -EIO;
+
+       default:
+               dev_err(dev, "%s: returned unknown value: 0x%02X\n",
+                       ret_desc, rx_cmd_ret_u8);
+               return -EBADMSG;
+       }
+}
+
+/**
+ * es58x_rx_cmd_ret_u32() - Handle the command return code received
+ *     from the ES58X device.
+ * @netdev: CAN network device.
+ * @cmd_ret_type: Type of the command which triggered the return code.
+ * @rx_cmd_ret_u32: error code as returned by the ES58X device.
+ *
+ * Handles the 32 bits command return code. The return value will
+ * eventually be used by es58x_handle_urb_cmd() function which will
+ * take proper actions in case of critical issues such and memory
+ * errors or bad CRC values.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+int es58x_rx_cmd_ret_u32(struct net_device *netdev,
+                        enum es58x_ret_type cmd_ret_type,
+                        enum es58x_ret_u32 rx_cmd_ret_u32)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       const struct es58x_operators *ops = priv->es58x_dev->ops;
+       const char *ret_desc = es58x_cmd_ret_desc(cmd_ret_type);
+
+       switch (rx_cmd_ret_u32) {
+       case ES58X_RET_U32_OK:
+               switch (cmd_ret_type) {
+               case ES58X_RET_TYPE_ENABLE_CHANNEL:
+                       es58x_can_reset_echo_fifo(netdev);
+                       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+                       netif_wake_queue(netdev);
+                       netdev_info(netdev,
+                                   "%s: %s (Serial Number %s): CAN%d channel becomes ready\n",
+                                   ret_desc, priv->es58x_dev->udev->product,
+                                   priv->es58x_dev->udev->serial,
+                                   priv->channel_idx + 1);
+                       break;
+
+               case ES58X_RET_TYPE_TX_MSG:
+                       if (IS_ENABLED(CONFIG_VERBOSE_DEBUG) && net_ratelimit())
+                               netdev_vdbg(netdev, "%s: OK\n", ret_desc);
+                       break;
+
+               default:
+                       netdev_dbg(netdev, "%s: OK\n", ret_desc);
+                       break;
+               }
+               return 0;
+
+       case ES58X_RET_U32_ERR_UNSPECIFIED_FAILURE:
+               if (cmd_ret_type == ES58X_RET_TYPE_ENABLE_CHANNEL) {
+                       int ret;
+
+                       netdev_warn(netdev,
+                                   "%s: channel is already opened, closing and re-openning it to reflect new configuration\n",
+                                   ret_desc);
+                       ret = ops->disable_channel(es58x_priv(netdev));
+                       if (ret)
+                               return ret;
+                       return ops->enable_channel(es58x_priv(netdev));
+               }
+               if (cmd_ret_type == ES58X_RET_TYPE_DISABLE_CHANNEL) {
+                       netdev_info(netdev,
+                                   "%s: channel is already closed\n", ret_desc);
+                       return 0;
+               }
+               netdev_err(netdev,
+                          "%s: unspecified failure\n", ret_desc);
+               return -EBADMSG;
+
+       case ES58X_RET_U32_ERR_NO_MEM:
+               netdev_err(netdev, "%s: device ran out of memory\n", ret_desc);
+               return -ENOMEM;
+
+       case ES58X_RET_U32_WARN_PARAM_ADJUSTED:
+               netdev_warn(netdev,
+                           "%s: some incompatible parameters have been adjusted\n",
+                           ret_desc);
+               return 0;
+
+       case ES58X_RET_U32_WARN_TX_MAYBE_REORDER:
+               netdev_warn(netdev,
+                           "%s: TX messages might have been reordered\n",
+                           ret_desc);
+               return 0;
+
+       case ES58X_RET_U32_ERR_TIMEDOUT:
+               netdev_err(netdev, "%s: command timed out\n", ret_desc);
+               return -ETIMEDOUT;
+
+       case ES58X_RET_U32_ERR_FIFO_FULL:
+               netdev_warn(netdev, "%s: fifo is full\n", ret_desc);
+               return 0;
+
+       case ES58X_RET_U32_ERR_BAD_CONFIG:
+               netdev_err(netdev, "%s: bad configuration\n", ret_desc);
+               return -EINVAL;
+
+       case ES58X_RET_U32_ERR_NO_RESOURCE:
+               netdev_err(netdev, "%s: no resource available\n", ret_desc);
+               return -EBUSY;
+
+       default:
+               netdev_err(netdev, "%s returned unknown value: 0x%08X\n",
+                          ret_desc, rx_cmd_ret_u32);
+               return -EBADMSG;
+       }
+}
+
+/**
+ * es58x_increment_rx_errors() - Increment the network devices' error
+ *     count.
+ * @es58x_dev: ES58X device.
+ *
+ * If an error occurs on the early stages on receiving an URB command,
+ * we might not be able to figure out on which network device the
+ * error occurred. In such case, we arbitrarily increment the error
+ * count of all the network devices attached to our ES58X device.
+ */
+static void es58x_increment_rx_errors(struct es58x_device *es58x_dev)
+{
+       int i;
+
+       for (i = 0; i < es58x_dev->num_can_ch; i++)
+               if (es58x_dev->netdev[i])
+                       es58x_dev->netdev[i]->stats.rx_errors++;
+}
+
+/**
+ * es58x_handle_urb_cmd() - Handle the URB command
+ * @es58x_dev: ES58X device.
+ * @urb_cmd: The URB command received from the ES58X device, might not
+ *     be aligned.
+ *
+ * Sends the URB command to the device specific function. Manages the
+ * errors thrown back by those functions.
+ */
+static void es58x_handle_urb_cmd(struct es58x_device *es58x_dev,
+                                const union es58x_urb_cmd *urb_cmd)
+{
+       const struct es58x_operators *ops = es58x_dev->ops;
+       size_t cmd_len;
+       int i, ret;
+
+       ret = ops->handle_urb_cmd(es58x_dev, urb_cmd);
+       switch (ret) {
+       case 0:         /* OK */
+               return;
+
+       case -ENODEV:
+               dev_err_ratelimited(es58x_dev->dev, "Device is not ready\n");
+               break;
+
+       case -EINVAL:
+       case -EMSGSIZE:
+       case -EBADRQC:
+       case -EBADMSG:
+       case -ECHRNG:
+       case -ETIMEDOUT:
+               cmd_len = es58x_get_urb_cmd_len(es58x_dev,
+                                               ops->get_msg_len(urb_cmd));
+               dev_err(es58x_dev->dev,
+                       "ops->handle_urb_cmd() returned error %pe",
+                       ERR_PTR(ret));
+               es58x_print_hex_dump(urb_cmd, cmd_len);
+               break;
+
+       case -EFAULT:
+       case -ENOMEM:
+       case -EIO:
+       default:
+               dev_crit(es58x_dev->dev,
+                        "ops->handle_urb_cmd() returned error %pe, detaching all network devices\n",
+                        ERR_PTR(ret));
+               for (i = 0; i < es58x_dev->num_can_ch; i++)
+                       if (es58x_dev->netdev[i])
+                               netif_device_detach(es58x_dev->netdev[i]);
+               if (es58x_dev->ops->reset_device)
+                       es58x_dev->ops->reset_device(es58x_dev);
+               break;
+       }
+
+       /* Because the urb command could not fully be parsed,
+        * channel_id is not confirmed. Incrementing rx_errors count
+        * of all channels.
+        */
+       es58x_increment_rx_errors(es58x_dev);
+}
+
+/**
+ * es58x_check_rx_urb() - Check the length and format of the URB command.
+ * @es58x_dev: ES58X device.
+ * @urb_cmd: The URB command received from the ES58X device, might not
+ *     be aligned.
+ * @urb_actual_len: The actual length of the URB command.
+ *
+ * Check if the first message of the received urb is valid, that is to
+ * say that both the header and the length are coherent.
+ *
+ * Return:
+ * the length of the first message of the URB on success.
+ *
+ * -ENODATA if the URB command is incomplete (in which case, the URB
+ * command should be buffered and combined with the next URB to try to
+ * reconstitute the URB command).
+ *
+ * -EOVERFLOW if the length is bigger than the maximum expected one.
+ *
+ * -EBADRQC if the start of frame does not match the expected value.
+ */
+static signed int es58x_check_rx_urb(struct es58x_device *es58x_dev,
+                                    const union es58x_urb_cmd *urb_cmd,
+                                    u32 urb_actual_len)
+{
+       const struct device *dev = es58x_dev->dev;
+       const struct es58x_parameters *param = es58x_dev->param;
+       u16 sof, msg_len;
+       signed int urb_cmd_len, ret;
+
+       if (urb_actual_len < param->urb_cmd_header_len) {
+               dev_vdbg(dev,
+                        "%s: Received %d bytes [%*ph]: header incomplete\n",
+                        __func__, urb_actual_len, urb_actual_len,
+                        urb_cmd->raw_cmd);
+               return -ENODATA;
+       }
+
+       sof = get_unaligned_le16(&urb_cmd->sof);
+       if (sof != param->rx_start_of_frame) {
+               dev_err_ratelimited(es58x_dev->dev,
+                                   "%s: Expected sequence 0x%04X for start of frame but got 0x%04X.\n",
+                                   __func__, param->rx_start_of_frame, sof);
+               return -EBADRQC;
+       }
+
+       msg_len = es58x_dev->ops->get_msg_len(urb_cmd);
+       urb_cmd_len = es58x_get_urb_cmd_len(es58x_dev, msg_len);
+       if (urb_cmd_len > param->rx_urb_cmd_max_len) {
+               dev_err_ratelimited(es58x_dev->dev,
+                                   "%s: Biggest expected size for rx urb_cmd is %u but receive a command of size %d\n",
+                                   __func__,
+                                   param->rx_urb_cmd_max_len, urb_cmd_len);
+               return -EOVERFLOW;
+       } else if (urb_actual_len < urb_cmd_len) {
+               dev_vdbg(dev, "%s: Received %02d/%02d bytes\n",
+                        __func__, urb_actual_len, urb_cmd_len);
+               return -ENODATA;
+       }
+
+       ret = es58x_check_crc(es58x_dev, urb_cmd, urb_cmd_len);
+       if (ret)
+               return ret;
+
+       return urb_cmd_len;
+}
+
+/**
+ * es58x_copy_to_cmd_buf() - Copy an array to the URB command buffer.
+ * @es58x_dev: ES58X device.
+ * @raw_cmd: the buffer we want to copy.
+ * @raw_cmd_len: length of @raw_cmd.
+ *
+ * Concatenates @raw_cmd_len bytes of @raw_cmd to the end of the URB
+ * command buffer.
+ *
+ * Return: zero on success, -EMSGSIZE if not enough space is available
+ * to do the copy.
+ */
+static int es58x_copy_to_cmd_buf(struct es58x_device *es58x_dev,
+                                u8 *raw_cmd, int raw_cmd_len)
+{
+       if (es58x_dev->rx_cmd_buf_len + raw_cmd_len >
+           es58x_dev->param->rx_urb_cmd_max_len)
+               return -EMSGSIZE;
+
+       memcpy(&es58x_dev->rx_cmd_buf.raw_cmd[es58x_dev->rx_cmd_buf_len],
+              raw_cmd, raw_cmd_len);
+       es58x_dev->rx_cmd_buf_len += raw_cmd_len;
+
+       return 0;
+}
+
+/**
+ * es58x_split_urb_try_recovery() - Try to recover bad URB sequences.
+ * @es58x_dev: ES58X device.
+ * @raw_cmd: pointer to the buffer we want to copy.
+ * @raw_cmd_len: length of @raw_cmd.
+ *
+ * Under some rare conditions, we might get incorrect URBs from the
+ * device. From our observations, one of the valid URB gets replaced
+ * by one from the past. The full root cause is not identified.
+ *
+ * This function looks for the next start of frame in the urb buffer
+ * in order to try to recover.
+ *
+ * Such behavior was not observed on the devices of the ES58X FD
+ * family and only seems to impact the ES581.4.
+ *
+ * Return: the number of bytes dropped on success, -EBADMSG if recovery failed.
+ */
+static int es58x_split_urb_try_recovery(struct es58x_device *es58x_dev,
+                                       u8 *raw_cmd, size_t raw_cmd_len)
+{
+       union es58x_urb_cmd *urb_cmd;
+       signed int urb_cmd_len;
+       u16 sof;
+       int dropped_bytes = 0;
+
+       es58x_increment_rx_errors(es58x_dev);
+
+       while (raw_cmd_len > sizeof(sof)) {
+               urb_cmd = (union es58x_urb_cmd *)raw_cmd;
+               sof = get_unaligned_le16(&urb_cmd->sof);
+
+               if (sof == es58x_dev->param->rx_start_of_frame) {
+                       urb_cmd_len = es58x_check_rx_urb(es58x_dev,
+                                                        urb_cmd, raw_cmd_len);
+                       if ((urb_cmd_len == -ENODATA) || urb_cmd_len > 0) {
+                               dev_info_ratelimited(es58x_dev->dev,
+                                                    "Recovery successful! Dropped %d bytes (urb_cmd_len: %d)\n",
+                                                    dropped_bytes,
+                                                    urb_cmd_len);
+                               return dropped_bytes;
+                       }
+               }
+               raw_cmd++;
+               raw_cmd_len--;
+               dropped_bytes++;
+       }
+
+       dev_warn_ratelimited(es58x_dev->dev, "%s: Recovery failed\n", __func__);
+       return -EBADMSG;
+}
+
+/**
+ * es58x_handle_incomplete_cmd() - Reconstitute an URB command from
+ *     different URB pieces.
+ * @es58x_dev: ES58X device.
+ * @urb: last urb buffer received.
+ *
+ * The device might split the URB commands in an arbitrary amount of
+ * pieces. This function concatenates those in an URB buffer until a
+ * full URB command is reconstituted and consume it.
+ *
+ * Return:
+ * number of bytes consumed from @urb if successful.
+ *
+ * -ENODATA if the URB command is still incomplete.
+ *
+ * -EBADMSG if the URB command is incorrect.
+ */
+static signed int es58x_handle_incomplete_cmd(struct es58x_device *es58x_dev,
+                                             struct urb *urb)
+{
+       size_t cpy_len;
+       signed int urb_cmd_len, tmp_cmd_buf_len, ret;
+
+       tmp_cmd_buf_len = es58x_dev->rx_cmd_buf_len;
+       cpy_len = min_t(int, es58x_dev->param->rx_urb_cmd_max_len -
+                       es58x_dev->rx_cmd_buf_len, urb->actual_length);
+       ret = es58x_copy_to_cmd_buf(es58x_dev, urb->transfer_buffer, cpy_len);
+       if (ret < 0)
+               return ret;
+
+       urb_cmd_len = es58x_check_rx_urb(es58x_dev, &es58x_dev->rx_cmd_buf,
+                                        es58x_dev->rx_cmd_buf_len);
+       if (urb_cmd_len == -ENODATA) {
+               return -ENODATA;
+       } else if (urb_cmd_len < 0) {
+               dev_err_ratelimited(es58x_dev->dev,
+                                   "Could not reconstitute incomplete command from previous URB, dropping %d bytes\n",
+                                   tmp_cmd_buf_len + urb->actual_length);
+               dev_err_ratelimited(es58x_dev->dev,
+                                   "Error code: %pe, es58x_dev->rx_cmd_buf_len: %d, urb->actual_length: %u\n",
+                                   ERR_PTR(urb_cmd_len),
+                                   tmp_cmd_buf_len, urb->actual_length);
+               es58x_print_hex_dump(&es58x_dev->rx_cmd_buf, tmp_cmd_buf_len);
+               es58x_print_hex_dump(urb->transfer_buffer, urb->actual_length);
+               return urb->actual_length;
+       }
+
+       es58x_handle_urb_cmd(es58x_dev, &es58x_dev->rx_cmd_buf);
+       return urb_cmd_len - tmp_cmd_buf_len;   /* consumed length */
+}
+
+/**
+ * es58x_split_urb() - Cut the received URB in individual URB commands.
+ * @es58x_dev: ES58X device.
+ * @urb: last urb buffer received.
+ *
+ * The device might send urb in bulk format (i.e. several URB commands
+ * concatenated together). This function will split all the commands
+ * contained in the urb.
+ *
+ * Return:
+ * number of bytes consumed from @urb if successful.
+ *
+ * -ENODATA if the URB command is incomplete.
+ *
+ * -EBADMSG if the URB command is incorrect.
+ */
+static signed int es58x_split_urb(struct es58x_device *es58x_dev,
+                                 struct urb *urb)
+{
+       union es58x_urb_cmd *urb_cmd;
+       u8 *raw_cmd = urb->transfer_buffer;
+       s32 raw_cmd_len = urb->actual_length;
+       int ret;
+
+       if (es58x_dev->rx_cmd_buf_len != 0) {
+               ret = es58x_handle_incomplete_cmd(es58x_dev, urb);
+               if (ret != -ENODATA)
+                       es58x_dev->rx_cmd_buf_len = 0;
+               if (ret < 0)
+                       return ret;
+
+               raw_cmd += ret;
+               raw_cmd_len -= ret;
+       }
+
+       while (raw_cmd_len > 0) {
+               if (raw_cmd[0] == ES58X_HEARTBEAT) {
+                       raw_cmd++;
+                       raw_cmd_len--;
+                       continue;
+               }
+               urb_cmd = (union es58x_urb_cmd *)raw_cmd;
+               ret = es58x_check_rx_urb(es58x_dev, urb_cmd, raw_cmd_len);
+               if (ret > 0) {
+                       es58x_handle_urb_cmd(es58x_dev, urb_cmd);
+               } else if (ret == -ENODATA) {
+                       es58x_copy_to_cmd_buf(es58x_dev, raw_cmd, raw_cmd_len);
+                       return -ENODATA;
+               } else if (ret < 0) {
+                       ret = es58x_split_urb_try_recovery(es58x_dev, raw_cmd,
+                                                          raw_cmd_len);
+                       if (ret < 0)
+                               return ret;
+               }
+               raw_cmd += ret;
+               raw_cmd_len -= ret;
+       }
+
+       return 0;
+}
+
+/**
+ * es58x_read_bulk_callback() - Callback for reading data from device.
+ * @urb: last urb buffer received.
+ *
+ * This function gets eventually called each time an URB is received
+ * from the ES58X device.
+ *
+ * Checks urb status, calls read function and resubmits urb read
+ * operation.
+ */
+static void es58x_read_bulk_callback(struct urb *urb)
+{
+       struct es58x_device *es58x_dev = urb->context;
+       const struct device *dev = es58x_dev->dev;
+       int i, ret;
+
+       switch (urb->status) {
+       case 0:         /* success */
+               break;
+
+       case -EOVERFLOW:
+               dev_err_ratelimited(dev, "%s: error %pe\n",
+                                   __func__, ERR_PTR(urb->status));
+               es58x_print_hex_dump_debug(urb->transfer_buffer,
+                                          urb->transfer_buffer_length);
+               goto resubmit_urb;
+
+       case -EPROTO:
+               dev_warn_ratelimited(dev, "%s: error %pe. Device unplugged?\n",
+                                    __func__, ERR_PTR(urb->status));
+               goto free_urb;
+
+       case -ENOENT:
+       case -EPIPE:
+               dev_err_ratelimited(dev, "%s: error %pe\n",
+                                   __func__, ERR_PTR(urb->status));
+               goto free_urb;
+
+       case -ESHUTDOWN:
+               dev_dbg_ratelimited(dev, "%s: error %pe\n",
+                                   __func__, ERR_PTR(urb->status));
+               goto free_urb;
+
+       default:
+               dev_err_ratelimited(dev, "%s: error %pe\n",
+                                   __func__, ERR_PTR(urb->status));
+               goto resubmit_urb;
+       }
+
+       ret = es58x_split_urb(es58x_dev, urb);
+       if ((ret != -ENODATA) && ret < 0) {
+               dev_err(es58x_dev->dev, "es58x_split_urb() returned error %pe",
+                       ERR_PTR(ret));
+               es58x_print_hex_dump_debug(urb->transfer_buffer,
+                                          urb->actual_length);
+
+               /* Because the urb command could not be parsed,
+                * channel_id is not confirmed. Incrementing rx_errors
+                * count of all channels.
+                */
+               es58x_increment_rx_errors(es58x_dev);
+       }
+
+ resubmit_urb:
+       usb_fill_bulk_urb(urb, es58x_dev->udev, es58x_dev->rx_pipe,
+                         urb->transfer_buffer, urb->transfer_buffer_length,
+                         es58x_read_bulk_callback, es58x_dev);
+
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret == -ENODEV) {
+               for (i = 0; i < es58x_dev->num_can_ch; i++)
+                       if (es58x_dev->netdev[i])
+                               netif_device_detach(es58x_dev->netdev[i]);
+       } else if (ret)
+               dev_err_ratelimited(dev,
+                                   "Failed resubmitting read bulk urb: %pe\n",
+                                   ERR_PTR(ret));
+       return;
+
+ free_urb:
+       usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+                         urb->transfer_buffer, urb->transfer_dma);
+}
+
+/**
+ * es58x_write_bulk_callback() - Callback after writing data to the device.
+ * @urb: urb buffer which was previously submitted.
+ *
+ * This function gets eventually called each time an URB was sent to
+ * the ES58X device.
+ *
+ * Puts the @urb back to the urbs idle anchor and tries to restart the
+ * network queue.
+ */
+static void es58x_write_bulk_callback(struct urb *urb)
+{
+       struct net_device *netdev = urb->context;
+       struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
+
+       switch (urb->status) {
+       case 0:         /* success */
+               break;
+
+       case -EOVERFLOW:
+               if (net_ratelimit())
+                       netdev_err(netdev, "%s: error %pe\n",
+                                  __func__, ERR_PTR(urb->status));
+               es58x_print_hex_dump(urb->transfer_buffer,
+                                    urb->transfer_buffer_length);
+               break;
+
+       case -ENOENT:
+               if (net_ratelimit())
+                       netdev_dbg(netdev, "%s: error %pe\n",
+                                  __func__, ERR_PTR(urb->status));
+               usb_free_coherent(urb->dev,
+                                 es58x_dev->param->tx_urb_cmd_max_len,
+                                 urb->transfer_buffer, urb->transfer_dma);
+               return;
+
+       default:
+               if (net_ratelimit())
+                       netdev_info(netdev, "%s: error %pe\n",
+                                   __func__, ERR_PTR(urb->status));
+               break;
+       }
+
+       usb_anchor_urb(urb, &es58x_dev->tx_urbs_idle);
+       atomic_inc(&es58x_dev->tx_urbs_idle_cnt);
+}
+
+/**
+ * es58x_alloc_urb() - Allocate memory for an URB and its transfer
+ *     buffer.
+ * @es58x_dev: ES58X device.
+ * @urb: URB to be allocated.
+ * @buf: used to return DMA address of buffer.
+ * @buf_len: requested buffer size.
+ * @mem_flags: affect whether allocation may block.
+ *
+ * Allocates an URB and its @transfer_buffer and set its @transfer_dma
+ * address.
+ *
+ * This function is used at start-up to allocate all RX URBs at once
+ * and during run time for TX URBs.
+ *
+ * Return: zero on success, -ENOMEM if no memory is available.
+ */
+static int es58x_alloc_urb(struct es58x_device *es58x_dev, struct urb **urb,
+                          u8 **buf, size_t buf_len, gfp_t mem_flags)
+{
+       *urb = usb_alloc_urb(0, mem_flags);
+       if (!*urb) {
+               dev_err(es58x_dev->dev, "No memory left for URBs\n");
+               return -ENOMEM;
+       }
+
+       *buf = usb_alloc_coherent(es58x_dev->udev, buf_len,
+                                 mem_flags, &(*urb)->transfer_dma);
+       if (!*buf) {
+               dev_err(es58x_dev->dev, "No memory left for USB buffer\n");
+               usb_free_urb(*urb);
+               return -ENOMEM;
+       }
+
+       (*urb)->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       return 0;
+}
+
+/**
+ * es58x_get_tx_urb() - Get an URB for transmission.
+ * @es58x_dev: ES58X device.
+ *
+ * Gets an URB from the idle urbs anchor or allocate a new one if the
+ * anchor is empty.
+ *
+ * If there are more than ES58X_TX_URBS_MAX in the idle anchor, do
+ * some garbage collection. The garbage collection is done here
+ * instead of within es58x_write_bulk_callback() because
+ * usb_free_coherent() should not be used in IRQ context:
+ * c.f. WARN_ON(irqs_disabled()) in dma_free_attrs().
+ *
+ * Return: a pointer to an URB on success, NULL if no memory is
+ * available.
+ */
+static struct urb *es58x_get_tx_urb(struct es58x_device *es58x_dev)
+{
+       atomic_t *idle_cnt = &es58x_dev->tx_urbs_idle_cnt;
+       struct urb *urb = usb_get_from_anchor(&es58x_dev->tx_urbs_idle);
+
+       if (!urb) {
+               size_t tx_buf_len;
+               u8 *buf;
+
+               tx_buf_len = es58x_dev->param->tx_urb_cmd_max_len;
+               if (es58x_alloc_urb(es58x_dev, &urb, &buf, tx_buf_len,
+                                   GFP_ATOMIC))
+                       return NULL;
+
+               usb_fill_bulk_urb(urb, es58x_dev->udev, es58x_dev->tx_pipe,
+                                 buf, tx_buf_len, NULL, NULL);
+               return urb;
+       }
+
+       while (atomic_dec_return(idle_cnt) > ES58X_TX_URBS_MAX) {
+               /* Garbage collector */
+               struct urb *tmp = usb_get_from_anchor(&es58x_dev->tx_urbs_idle);
+
+               if (!tmp)
+                       break;
+               usb_free_coherent(tmp->dev,
+                                 es58x_dev->param->tx_urb_cmd_max_len,
+                                 tmp->transfer_buffer, tmp->transfer_dma);
+               usb_free_urb(tmp);
+       }
+
+       return urb;
+}
+
+/**
+ * es58x_submit_urb() - Send data to the device.
+ * @es58x_dev: ES58X device.
+ * @urb: URB to be sent.
+ * @netdev: CAN network device.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_submit_urb(struct es58x_device *es58x_dev, struct urb *urb,
+                           struct net_device *netdev)
+{
+       int ret;
+
+       es58x_set_crc(urb->transfer_buffer, urb->transfer_buffer_length);
+       usb_fill_bulk_urb(urb, es58x_dev->udev, es58x_dev->tx_pipe,
+                         urb->transfer_buffer, urb->transfer_buffer_length,
+                         es58x_write_bulk_callback, netdev);
+       usb_anchor_urb(urb, &es58x_dev->tx_urbs_busy);
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret) {
+               netdev_err(netdev, "%s: USB send urb failure: %pe\n",
+                          __func__, ERR_PTR(ret));
+               usb_unanchor_urb(urb);
+               usb_free_coherent(urb->dev,
+                                 es58x_dev->param->tx_urb_cmd_max_len,
+                                 urb->transfer_buffer, urb->transfer_dma);
+       }
+       usb_free_urb(urb);
+
+       return ret;
+}
+
+/**
+ * es58x_send_msg() - Prepare an URB and submit it.
+ * @es58x_dev: ES58X device.
+ * @cmd_type: Command type.
+ * @cmd_id: Command ID.
+ * @msg: ES58X message to be sent.
+ * @msg_len: Length of @msg.
+ * @channel_idx: Index of the network device.
+ *
+ * Creates an URB command from a given message, sets the header and the
+ * CRC and then submits it.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+int es58x_send_msg(struct es58x_device *es58x_dev, u8 cmd_type, u8 cmd_id,
+                  const void *msg, u16 msg_len, int channel_idx)
+{
+       struct net_device *netdev;
+       union es58x_urb_cmd *urb_cmd;
+       struct urb *urb;
+       int urb_cmd_len;
+
+       if (channel_idx == ES58X_CHANNEL_IDX_NA)
+               netdev = es58x_dev->netdev[0];  /* Default to first channel */
+       else
+               netdev = es58x_dev->netdev[channel_idx];
+
+       urb_cmd_len = es58x_get_urb_cmd_len(es58x_dev, msg_len);
+       if (urb_cmd_len > es58x_dev->param->tx_urb_cmd_max_len)
+               return -EOVERFLOW;
+
+       urb = es58x_get_tx_urb(es58x_dev);
+       if (!urb)
+               return -ENOMEM;
+
+       urb_cmd = urb->transfer_buffer;
+       es58x_dev->ops->fill_urb_header(urb_cmd, cmd_type, cmd_id,
+                                       channel_idx, msg_len);
+       memcpy(&urb_cmd->raw_cmd[es58x_dev->param->urb_cmd_header_len],
+              msg, msg_len);
+       urb->transfer_buffer_length = urb_cmd_len;
+
+       return es58x_submit_urb(es58x_dev, urb, netdev);
+}
+
+/**
+ * es58x_alloc_rx_urbs() - Allocate RX URBs.
+ * @es58x_dev: ES58X device.
+ *
+ * Allocate URBs for reception and anchor them.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_alloc_rx_urbs(struct es58x_device *es58x_dev)
+{
+       const struct device *dev = es58x_dev->dev;
+       const struct es58x_parameters *param = es58x_dev->param;
+       size_t rx_buf_len = es58x_dev->rx_max_packet_size;
+       struct urb *urb;
+       u8 *buf;
+       int i;
+       int ret = -EINVAL;
+
+       for (i = 0; i < param->rx_urb_max; i++) {
+               ret = es58x_alloc_urb(es58x_dev, &urb, &buf, rx_buf_len,
+                                     GFP_KERNEL);
+               if (ret)
+                       break;
+
+               usb_fill_bulk_urb(urb, es58x_dev->udev, es58x_dev->rx_pipe,
+                                 buf, rx_buf_len, es58x_read_bulk_callback,
+                                 es58x_dev);
+               usb_anchor_urb(urb, &es58x_dev->rx_urbs);
+
+               ret = usb_submit_urb(urb, GFP_KERNEL);
+               if (ret) {
+                       usb_unanchor_urb(urb);
+                       usb_free_coherent(es58x_dev->udev, rx_buf_len,
+                                         buf, urb->transfer_dma);
+                       usb_free_urb(urb);
+                       break;
+               }
+               usb_free_urb(urb);
+       }
+
+       if (i == 0) {
+               dev_err(dev, "%s: Could not setup any rx URBs\n", __func__);
+               return ret;
+       }
+       dev_dbg(dev, "%s: Allocated %d rx URBs each of size %zu\n",
+               __func__, i, rx_buf_len);
+
+       return ret;
+}
+
+/**
+ * es58x_free_urbs() - Free all the TX and RX URBs.
+ * @es58x_dev: ES58X device.
+ */
+static void es58x_free_urbs(struct es58x_device *es58x_dev)
+{
+       struct urb *urb;
+
+       if (!usb_wait_anchor_empty_timeout(&es58x_dev->tx_urbs_busy, 1000)) {
+               dev_err(es58x_dev->dev, "%s: Timeout, some TX urbs still remain\n",
+                       __func__);
+               usb_kill_anchored_urbs(&es58x_dev->tx_urbs_busy);
+       }
+
+       while ((urb = usb_get_from_anchor(&es58x_dev->tx_urbs_idle)) != NULL) {
+               usb_free_coherent(urb->dev, es58x_dev->param->tx_urb_cmd_max_len,
+                                 urb->transfer_buffer, urb->transfer_dma);
+               usb_free_urb(urb);
+               atomic_dec(&es58x_dev->tx_urbs_idle_cnt);
+       }
+       if (atomic_read(&es58x_dev->tx_urbs_idle_cnt))
+               dev_err(es58x_dev->dev,
+                       "All idle urbs were freed but tx_urb_idle_cnt is %d\n",
+                       atomic_read(&es58x_dev->tx_urbs_idle_cnt));
+
+       usb_kill_anchored_urbs(&es58x_dev->rx_urbs);
+}
+
+/**
+ * es58x_open() - Enable the network device.
+ * @netdev: CAN network device.
+ *
+ * Called when the network transitions to the up state. Allocate the
+ * URB resources if needed and open the channel.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_open(struct net_device *netdev)
+{
+       struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
+       int ret;
+
+       if (atomic_inc_return(&es58x_dev->opened_channel_cnt) == 1) {
+               ret = es58x_alloc_rx_urbs(es58x_dev);
+               if (ret)
+                       return ret;
+
+               ret = es58x_set_realtime_diff_ns(es58x_dev);
+               if (ret)
+                       goto free_urbs;
+       }
+
+       ret = open_candev(netdev);
+       if (ret)
+               goto free_urbs;
+
+       ret = es58x_dev->ops->enable_channel(es58x_priv(netdev));
+       if (ret)
+               goto free_urbs;
+
+       netif_start_queue(netdev);
+
+       return ret;
+
+ free_urbs:
+       if (atomic_dec_and_test(&es58x_dev->opened_channel_cnt))
+               es58x_free_urbs(es58x_dev);
+       netdev_err(netdev, "%s: Could not open the network device: %pe\n",
+                  __func__, ERR_PTR(ret));
+
+       return ret;
+}
+
+/**
+ * es58x_stop() - Disable the network device.
+ * @netdev: CAN network device.
+ *
+ * Called when the network transitions to the down state. If all the
+ * channels of the device are closed, free the URB resources which are
+ * not needed anymore.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_stop(struct net_device *netdev)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       struct es58x_device *es58x_dev = priv->es58x_dev;
+       int ret;
+
+       netif_stop_queue(netdev);
+       ret = es58x_dev->ops->disable_channel(priv);
+       if (ret)
+               return ret;
+
+       priv->can.state = CAN_STATE_STOPPED;
+       es58x_can_reset_echo_fifo(netdev);
+       close_candev(netdev);
+
+       es58x_flush_pending_tx_msg(netdev);
+
+       if (atomic_dec_and_test(&es58x_dev->opened_channel_cnt))
+               es58x_free_urbs(es58x_dev);
+
+       return 0;
+}
+
+/**
+ * es58x_xmit_commit() - Send the bulk urb.
+ * @netdev: CAN network device.
+ *
+ * Do the bulk send. This function should be called only once by bulk
+ * transmission.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_xmit_commit(struct net_device *netdev)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       int ret;
+
+       if (!es58x_is_can_state_active(netdev))
+               return -ENETDOWN;
+
+       if (es58x_is_echo_skb_threshold_reached(priv))
+               netif_stop_queue(netdev);
+
+       ret = es58x_submit_urb(priv->es58x_dev, priv->tx_urb, netdev);
+       if (ret == 0)
+               priv->tx_urb = NULL;
+
+       return ret;
+}
+
+/**
+ * es58x_xmit_more() - Can we put more packets?
+ * @priv: ES58X private parameters related to the network device.
+ *
+ * Return: true if we can put more, false if it is time to send.
+ */
+static bool es58x_xmit_more(struct es58x_priv *priv)
+{
+       unsigned int free_slots =
+           priv->can.echo_skb_max - (priv->tx_head - priv->tx_tail);
+
+       return netdev_xmit_more() && free_slots > 0 &&
+               priv->tx_can_msg_cnt < priv->es58x_dev->param->tx_bulk_max;
+}
+
+/**
+ * es58x_start_xmit() - Transmit an skb.
+ * @skb: socket buffer of a CAN message.
+ * @netdev: CAN network device.
+ *
+ * Called when a packet needs to be transmitted.
+ *
+ * This function relies on Byte Queue Limits (BQL). The main benefit
+ * is to increase the throughput by allowing bulk transfers
+ * (c.f. xmit_more flag).
+ *
+ * Queues up to tx_bulk_max messages in &tx_urb buffer and does
+ * a bulk send of all messages in one single URB.
+ *
+ * Return: NETDEV_TX_OK regardless of if we could transmit the @skb or
+ *     had to drop it.
+ */
+static netdev_tx_t es58x_start_xmit(struct sk_buff *skb,
+                                   struct net_device *netdev)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       struct es58x_device *es58x_dev = priv->es58x_dev;
+       unsigned int frame_len;
+       int ret;
+
+       if (can_dropped_invalid_skb(netdev, skb)) {
+               if (priv->tx_urb)
+                       goto xmit_commit;
+               return NETDEV_TX_OK;
+       }
+
+       if (priv->tx_urb && priv->tx_can_msg_is_fd != can_is_canfd_skb(skb)) {
+               /* Can not do bulk send with mixed CAN and CAN FD frames. */
+               ret = es58x_xmit_commit(netdev);
+               if (ret)
+                       goto drop_skb;
+       }
+
+       if (!priv->tx_urb) {
+               priv->tx_urb = es58x_get_tx_urb(es58x_dev);
+               if (!priv->tx_urb) {
+                       ret = -ENOMEM;
+                       goto drop_skb;
+               }
+               priv->tx_can_msg_cnt = 0;
+               priv->tx_can_msg_is_fd = can_is_canfd_skb(skb);
+       }
+
+       ret = es58x_dev->ops->tx_can_msg(priv, skb);
+       if (ret)
+               goto drop_skb;
+
+       frame_len = can_skb_get_frame_len(skb);
+       ret = can_put_echo_skb(skb, netdev,
+                              priv->tx_head & es58x_dev->param->fifo_mask,
+                              frame_len);
+       if (ret)
+               goto xmit_failure;
+       netdev_sent_queue(netdev, frame_len);
+
+       priv->tx_head++;
+       priv->tx_can_msg_cnt++;
+
+ xmit_commit:
+       if (!es58x_xmit_more(priv)) {
+               ret = es58x_xmit_commit(netdev);
+               if (ret)
+                       goto xmit_failure;
+       }
+
+       return NETDEV_TX_OK;
+
+ drop_skb:
+       dev_kfree_skb(skb);
+       netdev->stats.tx_dropped++;
+ xmit_failure:
+       netdev_warn(netdev, "%s: send message failure: %pe\n",
+                   __func__, ERR_PTR(ret));
+       netdev->stats.tx_errors++;
+       es58x_flush_pending_tx_msg(netdev);
+       return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops es58x_netdev_ops = {
+       .ndo_open = es58x_open,
+       .ndo_stop = es58x_stop,
+       .ndo_start_xmit = es58x_start_xmit
+};
+
+/**
+ * es58x_set_mode() - Change network device mode.
+ * @netdev: CAN network device.
+ * @mode: either %CAN_MODE_START, %CAN_MODE_STOP or %CAN_MODE_SLEEP
+ *
+ * Currently, this function is only used to stop and restart the
+ * channel during a bus off event (c.f. es58x_rx_err_msg() and
+ * drivers/net/can/dev.c:can_restart() which are the two only
+ * callers).
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+
+       switch (mode) {
+       case CAN_MODE_START:
+               switch (priv->can.state) {
+               case CAN_STATE_BUS_OFF:
+                       return priv->es58x_dev->ops->enable_channel(priv);
+
+               case CAN_STATE_STOPPED:
+                       return es58x_open(netdev);
+
+               case CAN_STATE_ERROR_ACTIVE:
+               case CAN_STATE_ERROR_WARNING:
+               case CAN_STATE_ERROR_PASSIVE:
+               default:
+                       return 0;
+               }
+
+       case CAN_MODE_STOP:
+               switch (priv->can.state) {
+               case CAN_STATE_STOPPED:
+                       return 0;
+
+               case CAN_STATE_ERROR_ACTIVE:
+               case CAN_STATE_ERROR_WARNING:
+               case CAN_STATE_ERROR_PASSIVE:
+               case CAN_STATE_BUS_OFF:
+               default:
+                       return priv->es58x_dev->ops->disable_channel(priv);
+               }
+
+       case CAN_MODE_SLEEP:
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+/**
+ * es58x_init_priv() - Initialize private parameters.
+ * @es58x_dev: ES58X device.
+ * @priv: ES58X private parameters related to the network device.
+ * @channel_idx: Index of the network device.
+ */
+static void es58x_init_priv(struct es58x_device *es58x_dev,
+                           struct es58x_priv *priv, int channel_idx)
+{
+       const struct es58x_parameters *param = es58x_dev->param;
+       struct can_priv *can = &priv->can;
+
+       priv->es58x_dev = es58x_dev;
+       priv->channel_idx = channel_idx;
+       priv->tx_urb = NULL;
+       priv->tx_can_msg_cnt = 0;
+
+       can->bittiming_const = param->bittiming_const;
+       if (param->ctrlmode_supported & CAN_CTRLMODE_FD) {
+               can->data_bittiming_const = param->data_bittiming_const;
+               can->tdc_const = param->tdc_const;
+       }
+       can->bitrate_max = param->bitrate_max;
+       can->clock = param->clock;
+       can->state = CAN_STATE_STOPPED;
+       can->ctrlmode_supported = param->ctrlmode_supported;
+       can->do_set_mode = es58x_set_mode;
+}
+
+/**
+ * es58x_init_netdev() - Initialize the network device.
+ * @es58x_dev: ES58X device.
+ * @channel_idx: Index of the network device.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_init_netdev(struct es58x_device *es58x_dev, int channel_idx)
+{
+       struct net_device *netdev;
+       struct device *dev = es58x_dev->dev;
+       int ret;
+
+       netdev = alloc_candev(sizeof(struct es58x_priv),
+                             es58x_dev->param->fifo_mask + 1);
+       if (!netdev) {
+               dev_err(dev, "Could not allocate candev\n");
+               return -ENOMEM;
+       }
+       SET_NETDEV_DEV(netdev, dev);
+       es58x_dev->netdev[channel_idx] = netdev;
+       es58x_init_priv(es58x_dev, es58x_priv(netdev), channel_idx);
+
+       netdev->netdev_ops = &es58x_netdev_ops;
+       netdev->flags |= IFF_ECHO;      /* We support local echo */
+
+       ret = register_candev(netdev);
+       if (ret)
+               return ret;
+
+       netdev_queue_set_dql_min_limit(netdev_get_tx_queue(netdev, 0),
+                                      es58x_dev->param->dql_min_limit);
+
+       return ret;
+}
+
+/**
+ * es58x_get_product_info() - Get the product information and print them.
+ * @es58x_dev: ES58X device.
+ *
+ * Do a synchronous call to get the product information.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_get_product_info(struct es58x_device *es58x_dev)
+{
+       struct usb_device *udev = es58x_dev->udev;
+       const int es58x_prod_info_idx = 6;
+       /* Empirical tests show a prod_info length of maximum 83,
+        * below should be more than enough.
+        */
+       const size_t prod_info_len = 127;
+       char *prod_info;
+       int ret;
+
+       prod_info = kmalloc(prod_info_len, GFP_KERNEL);
+       if (!prod_info)
+               return -ENOMEM;
+
+       ret = usb_string(udev, es58x_prod_info_idx, prod_info, prod_info_len);
+       if (ret < 0) {
+               dev_err(es58x_dev->dev,
+                       "%s: Could not read the product info: %pe\n",
+                       __func__, ERR_PTR(ret));
+               goto out_free;
+       }
+       if (ret >= prod_info_len - 1) {
+               dev_warn(es58x_dev->dev,
+                        "%s: Buffer is too small, result might be truncated\n",
+                        __func__);
+       }
+       dev_info(es58x_dev->dev, "Product info: %s\n", prod_info);
+
+ out_free:
+       kfree(prod_info);
+       return ret < 0 ? ret : 0;
+}
+
+/**
+ * es58x_init_es58x_dev() - Initialize the ES58X device.
+ * @intf: USB interface.
+ * @p_es58x_dev: pointer to the address of the ES58X device.
+ * @driver_info: Quirks of the device.
+ *
+ * Return: zero on success, errno when any error occurs.
+ */
+static int es58x_init_es58x_dev(struct usb_interface *intf,
+                               struct es58x_device **p_es58x_dev,
+                               kernel_ulong_t driver_info)
+{
+       struct device *dev = &intf->dev;
+       struct es58x_device *es58x_dev;
+       const struct es58x_parameters *param;
+       const struct es58x_operators *ops;
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct usb_endpoint_descriptor *ep_in, *ep_out;
+       int ret;
+
+       dev_info(dev,
+                "Starting %s %s (Serial Number %s) driver version %s\n",
+                udev->manufacturer, udev->product, udev->serial, DRV_VERSION);
+
+       ret = usb_find_common_endpoints(intf->cur_altsetting, &ep_in, &ep_out,
+                                       NULL, NULL);
+       if (ret)
+               return ret;
+
+       if (driver_info & ES58X_FD_FAMILY) {
+               param = &es58x_fd_param;
+               ops = &es58x_fd_ops;
+       } else {
+               param = &es581_4_param;
+               ops = &es581_4_ops;
+       }
+
+       es58x_dev = kzalloc(es58x_sizeof_es58x_device(param), GFP_KERNEL);
+       if (!es58x_dev)
+               return -ENOMEM;
+
+       es58x_dev->param = param;
+       es58x_dev->ops = ops;
+       es58x_dev->dev = dev;
+       es58x_dev->udev = udev;
+
+       if (driver_info & ES58X_DUAL_CHANNEL)
+               es58x_dev->num_can_ch = 2;
+       else
+               es58x_dev->num_can_ch = 1;
+
+       init_usb_anchor(&es58x_dev->rx_urbs);
+       init_usb_anchor(&es58x_dev->tx_urbs_idle);
+       init_usb_anchor(&es58x_dev->tx_urbs_busy);
+       atomic_set(&es58x_dev->tx_urbs_idle_cnt, 0);
+       atomic_set(&es58x_dev->opened_channel_cnt, 0);
+       usb_set_intfdata(intf, es58x_dev);
+
+       es58x_dev->rx_pipe = usb_rcvbulkpipe(es58x_dev->udev,
+                                            ep_in->bEndpointAddress);
+       es58x_dev->tx_pipe = usb_sndbulkpipe(es58x_dev->udev,
+                                            ep_out->bEndpointAddress);
+       es58x_dev->rx_max_packet_size = le16_to_cpu(ep_in->wMaxPacketSize);
+
+       *p_es58x_dev = es58x_dev;
+
+       return 0;
+}
+
+/**
+ * es58x_probe() - Initialize the USB device.
+ * @intf: USB interface.
+ * @id: USB device ID.
+ *
+ * Return: zero on success, -ENODEV if the interface is not supported
+ * or errno when any other error occurs.
+ */
+static int es58x_probe(struct usb_interface *intf,
+                      const struct usb_device_id *id)
+{
+       struct es58x_device *es58x_dev;
+       int ch_idx, ret;
+
+       ret = es58x_init_es58x_dev(intf, &es58x_dev, id->driver_info);
+       if (ret)
+               return ret;
+
+       ret = es58x_get_product_info(es58x_dev);
+       if (ret)
+               goto cleanup_es58x_dev;
+
+       for (ch_idx = 0; ch_idx < es58x_dev->num_can_ch; ch_idx++) {
+               ret = es58x_init_netdev(es58x_dev, ch_idx);
+               if (ret)
+                       goto cleanup_candev;
+       }
+
+       return ret;
+
+ cleanup_candev:
+       for (ch_idx = 0; ch_idx < es58x_dev->num_can_ch; ch_idx++)
+               if (es58x_dev->netdev[ch_idx]) {
+                       unregister_candev(es58x_dev->netdev[ch_idx]);
+                       free_candev(es58x_dev->netdev[ch_idx]);
+               }
+ cleanup_es58x_dev:
+       kfree(es58x_dev);
+
+       return ret;
+}
+
+/**
+ * es58x_disconnect() - Disconnect the USB device.
+ * @intf: USB interface
+ *
+ * Called by the usb core when driver is unloaded or device is
+ * removed.
+ */
+static void es58x_disconnect(struct usb_interface *intf)
+{
+       struct es58x_device *es58x_dev = usb_get_intfdata(intf);
+       struct net_device *netdev;
+       int i;
+
+       dev_info(&intf->dev, "Disconnecting %s %s\n",
+                es58x_dev->udev->manufacturer, es58x_dev->udev->product);
+
+       for (i = 0; i < es58x_dev->num_can_ch; i++) {
+               netdev = es58x_dev->netdev[i];
+               if (!netdev)
+                       continue;
+               unregister_candev(netdev);
+               es58x_dev->netdev[i] = NULL;
+               free_candev(netdev);
+       }
+
+       es58x_free_urbs(es58x_dev);
+
+       kfree(es58x_dev);
+       usb_set_intfdata(intf, NULL);
+}
+
+static struct usb_driver es58x_driver = {
+       .name = ES58X_MODULE_NAME,
+       .probe = es58x_probe,
+       .disconnect = es58x_disconnect,
+       .id_table = es58x_id_table
+};
+
+module_usb_driver(es58x_driver);
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.h b/drivers/net/can/usb/etas_es58x/es58x_core.h
new file mode 100644 (file)
index 0000000..5f4e7dc
--- /dev/null
@@ -0,0 +1,700 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
+ *
+ * File es58x_core.h: All common definitions and declarations.
+ *
+ * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
+ * Copyright (c) 2020 ETAS K.K.. All rights reserved.
+ * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
+ */
+
+#ifndef __ES58X_COMMON_H__
+#define __ES58X_COMMON_H__
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+
+#include "es581_4.h"
+#include "es58x_fd.h"
+
+/* Driver constants */
+#define ES58X_RX_URBS_MAX 5    /* Empirical value */
+#define ES58X_TX_URBS_MAX 6    /* Empirical value */
+
+#define ES58X_MAX(param)                               \
+       (ES581_4_##param > ES58X_FD_##param ?           \
+               ES581_4_##param : ES58X_FD_##param)
+#define ES58X_TX_BULK_MAX ES58X_MAX(TX_BULK_MAX)
+#define ES58X_RX_BULK_MAX ES58X_MAX(RX_BULK_MAX)
+#define ES58X_ECHO_BULK_MAX ES58X_MAX(ECHO_BULK_MAX)
+#define ES58X_NUM_CAN_CH_MAX ES58X_MAX(NUM_CAN_CH)
+
+/* Use this when channel index is irrelevant (e.g. device
+ * timestamp).
+ */
+#define ES58X_CHANNEL_IDX_NA 0xFF
+#define ES58X_EMPTY_MSG NULL
+
+/* Threshold on consecutive CAN_STATE_ERROR_PASSIVE. If we receive
+ * ES58X_CONSECUTIVE_ERR_PASSIVE_MAX times the event
+ * ES58X_ERR_CRTL_PASSIVE in a row without any successful RX or TX,
+ * we force the device to switch to CAN_STATE_BUS_OFF state.
+ */
+#define ES58X_CONSECUTIVE_ERR_PASSIVE_MAX 254
+
+/* A magic number sent by the ES581.4 to inform it is alive. */
+#define ES58X_HEARTBEAT 0x11
+
+/**
+ * enum es58x_driver_info - Quirks of the device.
+ * @ES58X_DUAL_CHANNEL: Device has two CAN channels. If this flag is
+ *     not set, it is implied that the device has only one CAN
+ *     channel.
+ * @ES58X_FD_FAMILY: Device is CAN-FD capable. If this flag is not
+ *     set, the device only supports classical CAN.
+ */
+enum es58x_driver_info {
+       ES58X_DUAL_CHANNEL = BIT(0),
+       ES58X_FD_FAMILY = BIT(1)
+};
+
+enum es58x_echo {
+       ES58X_ECHO_OFF = 0,
+       ES58X_ECHO_ON = 1
+};
+
+/**
+ * enum es58x_physical_layer - Type of the physical layer.
+ * @ES58X_PHYSICAL_LAYER_HIGH_SPEED: High-speed CAN (c.f. ISO
+ *     11898-2).
+ *
+ * Some products of the ETAS portfolio also support low-speed CAN
+ * (c.f. ISO 11898-3). However, all the devices in scope of this
+ * driver do not support the option, thus, the enum has only one
+ * member.
+ */
+enum es58x_physical_layer {
+       ES58X_PHYSICAL_LAYER_HIGH_SPEED = 1
+};
+
+enum es58x_samples_per_bit {
+       ES58X_SAMPLES_PER_BIT_ONE = 1,
+       ES58X_SAMPLES_PER_BIT_THREE = 2
+};
+
+/**
+ * enum es58x_sync_edge - Synchronization method.
+ * @ES58X_SYNC_EDGE_SINGLE: ISO CAN specification defines the use of a
+ *     single edge synchronization.  The synchronization should be
+ *     done on recessive to dominant level change.
+ *
+ * For information, ES582.1 and ES584.1 also support a double
+ * synchronization, requiring both recessive to dominant then dominant
+ * to recessive level change. However, this is not supported in
+ * SocketCAN framework, thus, the enum has only one member.
+ */
+enum es58x_sync_edge {
+       ES58X_SYNC_EDGE_SINGLE = 1
+};
+
+/**
+ * enum es58x_flag - CAN flags for RX/TX messages.
+ * @ES58X_FLAG_EFF: Extended Frame Format (EFF).
+ * @ES58X_FLAG_RTR: Remote Transmission Request (RTR).
+ * @ES58X_FLAG_FD_BRS: Bit rate switch (BRS): second bitrate for
+ *     payload data.
+ * @ES58X_FLAG_FD_ESI: Error State Indicator (ESI): tell if the
+ *     transmitting node is in error passive mode.
+ * @ES58X_FLAG_FD_DATA: CAN FD frame.
+ */
+enum es58x_flag {
+       ES58X_FLAG_EFF = BIT(0),
+       ES58X_FLAG_RTR = BIT(1),
+       ES58X_FLAG_FD_BRS = BIT(3),
+       ES58X_FLAG_FD_ESI = BIT(5),
+       ES58X_FLAG_FD_DATA = BIT(6)
+};
+
+/**
+ * enum es58x_err - CAN error detection.
+ * @ES58X_ERR_OK: No errors.
+ * @ES58X_ERR_PROT_STUFF: Bit stuffing error: more than 5 consecutive
+ *     equal bits.
+ * @ES58X_ERR_PROT_FORM: Frame format error.
+ * @ES58X_ERR_ACK: Received no ACK on transmission.
+ * @ES58X_ERR_PROT_BIT: Single bit error.
+ * @ES58X_ERR_PROT_CRC: Incorrect 15, 17 or 21 bits CRC.
+ * @ES58X_ERR_PROT_BIT1: Unable to send recessive bit: tried to send
+ *     recessive bit 1 but monitored dominant bit 0.
+ * @ES58X_ERR_PROT_BIT0: Unable to send dominant bit: tried to send
+ *     dominant bit 0 but monitored recessive bit 1.
+ * @ES58X_ERR_PROT_OVERLOAD: Bus overload.
+ * @ES58X_ERR_PROT_UNSPEC: Unspecified.
+ *
+ * Please refer to ISO 11898-1:2015, section 10.11 "Error detection"
+ * and section 10.13 "Overload signaling" for additional details.
+ */
+enum es58x_err {
+       ES58X_ERR_OK = 0,
+       ES58X_ERR_PROT_STUFF = BIT(0),
+       ES58X_ERR_PROT_FORM = BIT(1),
+       ES58X_ERR_ACK = BIT(2),
+       ES58X_ERR_PROT_BIT = BIT(3),
+       ES58X_ERR_PROT_CRC = BIT(4),
+       ES58X_ERR_PROT_BIT1 = BIT(5),
+       ES58X_ERR_PROT_BIT0 = BIT(6),
+       ES58X_ERR_PROT_OVERLOAD = BIT(7),
+       ES58X_ERR_PROT_UNSPEC = BIT(31)
+};
+
+/**
+ * enum es58x_event - CAN error codes returned by the device.
+ * @ES58X_EVENT_OK: No errors.
+ * @ES58X_EVENT_CRTL_ACTIVE: Active state: both TR and RX error count
+ *     is less than 128.
+ * @ES58X_EVENT_CRTL_PASSIVE: Passive state: either TX or RX error
+ *     count is greater than 127.
+ * @ES58X_EVENT_CRTL_WARNING: Warning state: either TX or RX error
+ *     count is greater than 96.
+ * @ES58X_EVENT_BUSOFF: Bus off.
+ * @ES58X_EVENT_SINGLE_WIRE: Lost connection on either CAN high or CAN
+ *     low.
+ *
+ * Please refer to ISO 11898-1:2015, section 12.1.4 "Rules of fault
+ * confinement" for additional details.
+ */
+enum es58x_event {
+       ES58X_EVENT_OK = 0,
+       ES58X_EVENT_CRTL_ACTIVE = BIT(0),
+       ES58X_EVENT_CRTL_PASSIVE = BIT(1),
+       ES58X_EVENT_CRTL_WARNING = BIT(2),
+       ES58X_EVENT_BUSOFF = BIT(3),
+       ES58X_EVENT_SINGLE_WIRE = BIT(4)
+};
+
+/* enum es58x_ret_u8 - Device return error codes, 8 bit format.
+ *
+ * Specific to ES581.4.
+ */
+enum es58x_ret_u8 {
+       ES58X_RET_U8_OK = 0x00,
+       ES58X_RET_U8_ERR_UNSPECIFIED_FAILURE = 0x80,
+       ES58X_RET_U8_ERR_NO_MEM = 0x81,
+       ES58X_RET_U8_ERR_BAD_CRC = 0x99
+};
+
+/* enum es58x_ret_u32 - Device return error codes, 32 bit format.
+ */
+enum es58x_ret_u32 {
+       ES58X_RET_U32_OK = 0x00000000UL,
+       ES58X_RET_U32_ERR_UNSPECIFIED_FAILURE = 0x80000000UL,
+       ES58X_RET_U32_ERR_NO_MEM = 0x80004001UL,
+       ES58X_RET_U32_WARN_PARAM_ADJUSTED = 0x40004000UL,
+       ES58X_RET_U32_WARN_TX_MAYBE_REORDER = 0x40004001UL,
+       ES58X_RET_U32_ERR_TIMEDOUT = 0x80000008UL,
+       ES58X_RET_U32_ERR_FIFO_FULL = 0x80003002UL,
+       ES58X_RET_U32_ERR_BAD_CONFIG = 0x80004000UL,
+       ES58X_RET_U32_ERR_NO_RESOURCE = 0x80004002UL
+};
+
+/* enum es58x_ret_type - Type of the command returned by the ES58X
+ *     device.
+ */
+enum es58x_ret_type {
+       ES58X_RET_TYPE_SET_BITTIMING,
+       ES58X_RET_TYPE_ENABLE_CHANNEL,
+       ES58X_RET_TYPE_DISABLE_CHANNEL,
+       ES58X_RET_TYPE_TX_MSG,
+       ES58X_RET_TYPE_RESET_RX,
+       ES58X_RET_TYPE_RESET_TX,
+       ES58X_RET_TYPE_DEVICE_ERR
+};
+
+union es58x_urb_cmd {
+       struct es581_4_urb_cmd es581_4_urb_cmd;
+       struct es58x_fd_urb_cmd es58x_fd_urb_cmd;
+       struct {                /* Common header parts of all variants */
+               __le16 sof;
+               u8 cmd_type;
+               u8 cmd_id;
+       } __packed;
+       u8 raw_cmd[0];
+};
+
+/**
+ * struct es58x_priv - All information specific to a CAN channel.
+ * @can: struct can_priv must be the first member (Socket CAN relies
+ *     on the fact that function netdev_priv() returns a pointer to
+ *     a struct can_priv).
+ * @es58x_dev: pointer to the corresponding ES58X device.
+ * @tx_urb: Used as a buffer to concatenate the TX messages and to do
+ *     a bulk send. Please refer to es58x_start_xmit() for more
+ *     details.
+ * @tx_tail: Index of the oldest packet still pending for
+ *     completion. @tx_tail & echo_skb_mask represents the beginning
+ *     of the echo skb FIFO, i.e. index of the first element.
+ * @tx_head: Index of the next packet to be sent to the
+ *     device. @tx_head & echo_skb_mask represents the end of the
+ *     echo skb FIFO plus one, i.e. the first free index.
+ * @tx_can_msg_cnt: Number of messages in @tx_urb.
+ * @tx_can_msg_is_fd: false: all messages in @tx_urb are Classical
+ *     CAN, true: all messages in @tx_urb are CAN FD. Rationale:
+ *     ES58X FD devices do not allow to mix Classical CAN and FD CAN
+ *     frames in one single bulk transmission.
+ * @err_passive_before_rtx_success: The ES58X device might enter in a
+ *     state in which it keeps alternating between error passive
+ *     and active states. This counter keeps track of the number of
+ *     error passive and if it gets bigger than
+ *     ES58X_CONSECUTIVE_ERR_PASSIVE_MAX, es58x_rx_err_msg() will
+ *     force the status to bus-off.
+ * @channel_idx: Channel index, starts at zero.
+ */
+struct es58x_priv {
+       struct can_priv can;
+       struct es58x_device *es58x_dev;
+       struct urb *tx_urb;
+
+       u32 tx_tail;
+       u32 tx_head;
+
+       u8 tx_can_msg_cnt;
+       bool tx_can_msg_is_fd;
+
+       u8 err_passive_before_rtx_success;
+
+       u8 channel_idx;
+};
+
+/**
+ * struct es58x_parameters - Constant parameters of a given hardware
+ *     variant.
+ * @bittiming_const: Nominal bittimming constant parameters.
+ * @data_bittiming_const: Data bittiming constant parameters.
+ * @tdc_const: Transmission Delay Compensation constant parameters.
+ * @bitrate_max: Maximum bitrate supported by the device.
+ * @clock: CAN clock parameters.
+ * @ctrlmode_supported: List of supported modes. Please refer to
+ *     can/netlink.h file for additional details.
+ * @tx_start_of_frame: Magic number at the beginning of each TX URB
+ *     command.
+ * @rx_start_of_frame: Magic number at the beginning of each RX URB
+ *     command.
+ * @tx_urb_cmd_max_len: Maximum length of a TX URB command.
+ * @rx_urb_cmd_max_len: Maximum length of a RX URB command.
+ * @fifo_mask: Bit mask to quickly convert the tx_tail and tx_head
+ *     field of the struct es58x_priv into echo_skb
+ *     indexes. Properties: @fifo_mask = echos_skb_max - 1 where
+ *     echo_skb_max must be a power of two. Also, echo_skb_max must
+ *     not exceed the maximum size of the device internal TX FIFO
+ *     length. This parameter is used to control the network queue
+ *     wake/stop logic.
+ * @dql_min_limit: Dynamic Queue Limits (DQL) absolute minimum limit
+ *     of bytes allowed to be queued on this network device transmit
+ *     queue. Used by the Byte Queue Limits (BQL) to determine how
+ *     frequently the xmit_more flag will be set to true in
+ *     es58x_start_xmit(). Set this value higher to optimize for
+ *     throughput but be aware that it might have a negative impact
+ *     on the latency! This value can also be set dynamically. Please
+ *     refer to Documentation/ABI/testing/sysfs-class-net-queues for
+ *     more details.
+ * @tx_bulk_max: Maximum number of TX messages that can be sent in one
+ *     single URB packet.
+ * @urb_cmd_header_len: Length of the URB command header.
+ * @rx_urb_max: Number of RX URB to be allocated during device probe.
+ * @tx_urb_max: Number of TX URB to be allocated during device probe.
+ */
+struct es58x_parameters {
+       const struct can_bittiming_const *bittiming_const;
+       const struct can_bittiming_const *data_bittiming_const;
+       const struct can_tdc_const *tdc_const;
+       u32 bitrate_max;
+       struct can_clock clock;
+       u32 ctrlmode_supported;
+       u16 tx_start_of_frame;
+       u16 rx_start_of_frame;
+       u16 tx_urb_cmd_max_len;
+       u16 rx_urb_cmd_max_len;
+       u16 fifo_mask;
+       u16 dql_min_limit;
+       u8 tx_bulk_max;
+       u8 urb_cmd_header_len;
+       u8 rx_urb_max;
+       u8 tx_urb_max;
+};
+
+/**
+ * struct es58x_operators - Function pointers used to encode/decode
+ *     the TX/RX messages.
+ * @get_msg_len: Get field msg_len of the urb_cmd. The offset of
+ *     msg_len inside urb_cmd depends of the device model.
+ * @handle_urb_cmd: Decode the URB command received from the device
+ *     and dispatch it to the relevant sub function.
+ * @fill_urb_header: Fill the header of urb_cmd.
+ * @tx_can_msg: Encode a TX CAN message and add it to the bulk buffer
+ *     cmd_buf of es58x_dev.
+ * @enable_channel: Start the CAN channel.
+ * @disable_channel: Stop the CAN channel.
+ * @reset_device: Full reset of the device. N.B: this feature is only
+ *     present on the ES581.4. For ES58X FD devices, this field is
+ *     set to NULL.
+ * @get_timestamp: Request a timestamp from the ES58X device.
+ */
+struct es58x_operators {
+       u16 (*get_msg_len)(const union es58x_urb_cmd *urb_cmd);
+       int (*handle_urb_cmd)(struct es58x_device *es58x_dev,
+                             const union es58x_urb_cmd *urb_cmd);
+       void (*fill_urb_header)(union es58x_urb_cmd *urb_cmd, u8 cmd_type,
+                               u8 cmd_id, u8 channel_idx, u16 cmd_len);
+       int (*tx_can_msg)(struct es58x_priv *priv, const struct sk_buff *skb);
+       int (*enable_channel)(struct es58x_priv *priv);
+       int (*disable_channel)(struct es58x_priv *priv);
+       int (*reset_device)(struct es58x_device *es58x_dev);
+       int (*get_timestamp)(struct es58x_device *es58x_dev);
+};
+
+/**
+ * struct es58x_device - All information specific to an ES58X device.
+ * @dev: Device information.
+ * @udev: USB device information.
+ * @netdev: Array of our CAN channels.
+ * @param: The constant parameters.
+ * @ops: Operators.
+ * @rx_pipe: USB reception pipe.
+ * @tx_pipe: USB transmission pipe.
+ * @rx_urbs: Anchor for received URBs.
+ * @tx_urbs_busy: Anchor for TX URBs which were send to the device.
+ * @tx_urbs_idle: Anchor for TX USB which are idle. This driver
+ *     allocates the memory for the URBs during the probe. When a TX
+ *     URB is needed, it can be taken from this anchor. The network
+ *     queue wake/stop logic should prevent this URB from getting
+ *     empty. Please refer to es58x_get_tx_urb() for more details.
+ * @tx_urbs_idle_cnt: number of urbs in @tx_urbs_idle.
+ * @opened_channel_cnt: number of channels opened (c.f. es58x_open()
+ *     and es58x_stop()).
+ * @ktime_req_ns: kernel timestamp when es58x_set_realtime_diff_ns()
+ *     was called.
+ * @realtime_diff_ns: difference in nanoseconds between the clocks of
+ *     the ES58X device and the kernel.
+ * @timestamps: a temporary buffer to store the time stamps before
+ *     feeding them to es58x_can_get_echo_skb(). Can only be used
+ *     in RX branches.
+ * @rx_max_packet_size: Maximum length of bulk-in URB.
+ * @num_can_ch: Number of CAN channel (i.e. number of elements of @netdev).
+ * @rx_cmd_buf_len: Length of @rx_cmd_buf.
+ * @rx_cmd_buf: The device might split the URB commands in an
+ *     arbitrary amount of pieces. This buffer is used to concatenate
+ *     all those pieces. Can only be used in RX branches. This field
+ *     has to be the last one of the structure because it is has a
+ *     flexible size (c.f. es58x_sizeof_es58x_device() function).
+ */
+struct es58x_device {
+       struct device *dev;
+       struct usb_device *udev;
+       struct net_device *netdev[ES58X_NUM_CAN_CH_MAX];
+
+       const struct es58x_parameters *param;
+       const struct es58x_operators *ops;
+
+       int rx_pipe;
+       int tx_pipe;
+
+       struct usb_anchor rx_urbs;
+       struct usb_anchor tx_urbs_busy;
+       struct usb_anchor tx_urbs_idle;
+       atomic_t tx_urbs_idle_cnt;
+       atomic_t opened_channel_cnt;
+
+       u64 ktime_req_ns;
+       s64 realtime_diff_ns;
+
+       u64 timestamps[ES58X_ECHO_BULK_MAX];
+
+       u16 rx_max_packet_size;
+       u8 num_can_ch;
+
+       u16 rx_cmd_buf_len;
+       union es58x_urb_cmd rx_cmd_buf;
+};
+
+/**
+ * es58x_sizeof_es58x_device() - Calculate the maximum length of
+ *     struct es58x_device.
+ * @es58x_dev_param: The constant parameters of the device.
+ *
+ * The length of struct es58x_device depends on the length of its last
+ * field: rx_cmd_buf. This macro allows to optimize the memory
+ * allocation.
+ *
+ * Return: length of struct es58x_device.
+ */
+static inline size_t es58x_sizeof_es58x_device(const struct es58x_parameters
+                                              *es58x_dev_param)
+{
+       return offsetof(struct es58x_device, rx_cmd_buf) +
+               es58x_dev_param->rx_urb_cmd_max_len;
+}
+
+static inline int __es58x_check_msg_len(const struct device *dev,
+                                       const char *stringified_msg,
+                                       size_t actual_len, size_t expected_len)
+{
+       if (expected_len != actual_len) {
+               dev_err(dev,
+                       "Length of %s is %zu but received command is %zu.\n",
+                       stringified_msg, expected_len, actual_len);
+               return -EMSGSIZE;
+       }
+       return 0;
+}
+
+/**
+ * es58x_check_msg_len() - Check the size of a received message.
+ * @dev: Device, used to print error messages.
+ * @msg: Received message, must not be a pointer.
+ * @actual_len: Length of the message as advertised in the command header.
+ *
+ * Must be a macro in order to accept the different types of messages
+ * as an input. Can be use with any of the messages which have a fixed
+ * length. Check for an exact match of the size.
+ *
+ * Return: zero on success, -EMSGSIZE if @actual_len differs from the
+ * expected length.
+ */
+#define es58x_check_msg_len(dev, msg, actual_len)                      \
+       __es58x_check_msg_len(dev, __stringify(msg),                    \
+                             actual_len, sizeof(msg))
+
+static inline int __es58x_check_msg_max_len(const struct device *dev,
+                                           const char *stringified_msg,
+                                           size_t actual_len,
+                                           size_t expected_len)
+{
+       if (actual_len > expected_len) {
+               dev_err(dev,
+                       "Maximum length for %s is %zu but received command is %zu.\n",
+                       stringified_msg, expected_len, actual_len);
+               return -EOVERFLOW;
+       }
+       return 0;
+}
+
+/**
+ * es58x_check_msg_max_len() - Check the maximum size of a received message.
+ * @dev: Device, used to print error messages.
+ * @msg: Received message, must not be a pointer.
+ * @actual_len: Length of the message as advertised in the command header.
+ *
+ * Must be a macro in order to accept the different types of messages
+ * as an input. To be used with the messages of variable sizes. Only
+ * check that the message is not bigger than the maximum expected
+ * size.
+ *
+ * Return: zero on success, -EOVERFLOW if @actual_len is greater than
+ * the expected length.
+ */
+#define es58x_check_msg_max_len(dev, msg, actual_len)                  \
+       __es58x_check_msg_max_len(dev, __stringify(msg),                \
+                                 actual_len, sizeof(msg))
+
+static inline int __es58x_msg_num_element(const struct device *dev,
+                                         const char *stringified_msg,
+                                         size_t actual_len, size_t msg_len,
+                                         size_t elem_len)
+{
+       size_t actual_num_elem = actual_len / elem_len;
+       size_t expected_num_elem = msg_len / elem_len;
+
+       if (actual_num_elem == 0) {
+               dev_err(dev,
+                       "Minimum length for %s is %zu but received command is %zu.\n",
+                       stringified_msg, elem_len, actual_len);
+               return -EMSGSIZE;
+       } else if ((actual_len % elem_len) != 0) {
+               dev_err(dev,
+                       "Received command length: %zu is not a multiple of %s[0]: %zu\n",
+                       actual_len, stringified_msg, elem_len);
+               return -EMSGSIZE;
+       } else if (actual_num_elem > expected_num_elem) {
+               dev_err(dev,
+                       "Array %s is supposed to have %zu elements each of size %zu...\n",
+                       stringified_msg, expected_num_elem, elem_len);
+               dev_err(dev,
+                       "... But received command has %zu elements (total length %zu).\n",
+                       actual_num_elem, actual_len);
+               return -EOVERFLOW;
+       }
+       return actual_num_elem;
+}
+
+/**
+ * es58x_msg_num_element() - Check size and give the number of
+ *     elements in a message of array type.
+ * @dev: Device, used to print error messages.
+ * @msg: Received message, must be an array.
+ * @actual_len: Length of the message as advertised in the command
+ *     header.
+ *
+ * Must be a macro in order to accept the different types of messages
+ * as an input. To be used on message of array type. Array's element
+ * has to be of fixed size (else use es58x_check_msg_max_len()). Check
+ * that the total length is an exact multiple of the length of a
+ * single element.
+ *
+ * Return: number of elements in the array on success, -EOVERFLOW if
+ * @actual_len is greater than the expected length, -EMSGSIZE if
+ * @actual_len is not a multiple of a single element.
+ */
+#define es58x_msg_num_element(dev, msg, actual_len)                    \
+({                                                                     \
+       size_t __elem_len = sizeof((msg)[0]) + __must_be_array(msg);    \
+       __es58x_msg_num_element(dev, __stringify(msg), actual_len,      \
+                               sizeof(msg), __elem_len);               \
+})
+
+/**
+ * es58x_priv() - Get the priv member and cast it to struct es58x_priv.
+ * @netdev: CAN network device.
+ *
+ * Return: ES58X device.
+ */
+static inline struct es58x_priv *es58x_priv(struct net_device *netdev)
+{
+       return (struct es58x_priv *)netdev_priv(netdev);
+}
+
+/**
+ * ES58X_SIZEOF_URB_CMD() - Calculate the maximum length of an urb
+ *     command for a given message field name.
+ * @es58x_urb_cmd_type: type (either "struct es581_4_urb_cmd" or
+ *     "struct es58x_fd_urb_cmd").
+ * @msg_field: name of the message field.
+ *
+ * Must be a macro in order to accept the different command types as
+ * an input.
+ *
+ * Return: length of the urb command.
+ */
+#define ES58X_SIZEOF_URB_CMD(es58x_urb_cmd_type, msg_field)            \
+       (offsetof(es58x_urb_cmd_type, raw_msg)                          \
+               + sizeof_field(es58x_urb_cmd_type, msg_field)           \
+               + sizeof_field(es58x_urb_cmd_type,                      \
+                              reserved_for_crc16_do_not_use))
+
+/**
+ * es58x_get_urb_cmd_len() - Calculate the actual length of an urb
+ *     command for a given message length.
+ * @es58x_dev: ES58X device.
+ * @msg_len: Length of the message.
+ *
+ * Add the header and CRC lengths to the message length.
+ *
+ * Return: length of the urb command.
+ */
+static inline size_t es58x_get_urb_cmd_len(struct es58x_device *es58x_dev,
+                                          u16 msg_len)
+{
+       return es58x_dev->param->urb_cmd_header_len + msg_len + sizeof(u16);
+}
+
+/**
+ * es58x_get_netdev() - Get the network device.
+ * @es58x_dev: ES58X device.
+ * @channel_no: The channel number as advertised in the urb command.
+ * @channel_idx_offset: Some of the ES58x starts channel numbering
+ *     from 0 (ES58X FD), others from 1 (ES581.4).
+ * @netdev: CAN network device.
+ *
+ * Do a sanity check on the index provided by the device.
+ *
+ * Return: zero on success, -ECHRNG if the received channel number is
+ *     out of range and -ENODEV if the network device is not yet
+ *     configured.
+ */
+static inline int es58x_get_netdev(struct es58x_device *es58x_dev,
+                                  int channel_no, int channel_idx_offset,
+                                  struct net_device **netdev)
+{
+       int channel_idx = channel_no - channel_idx_offset;
+
+       *netdev = NULL;
+       if (channel_idx < 0 || channel_idx >= es58x_dev->num_can_ch)
+               return -ECHRNG;
+
+       *netdev = es58x_dev->netdev[channel_idx];
+       if (!netdev || !netif_device_present(*netdev))
+               return -ENODEV;
+
+       return 0;
+}
+
+/**
+ * es58x_get_raw_can_id() - Get the CAN ID.
+ * @cf: CAN frame.
+ *
+ * Mask the CAN ID in order to only keep the significant bits.
+ *
+ * Return: the raw value of the CAN ID.
+ */
+static inline int es58x_get_raw_can_id(const struct can_frame *cf)
+{
+       if (cf->can_id & CAN_EFF_FLAG)
+               return cf->can_id & CAN_EFF_MASK;
+       else
+               return cf->can_id & CAN_SFF_MASK;
+}
+
+/**
+ * es58x_get_flags() - Get the CAN flags.
+ * @skb: socket buffer of a CAN message.
+ *
+ * Return: the CAN flag as an enum es58x_flag.
+ */
+static inline enum es58x_flag es58x_get_flags(const struct sk_buff *skb)
+{
+       struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+       enum es58x_flag es58x_flags = 0;
+
+       if (cf->can_id & CAN_EFF_FLAG)
+               es58x_flags |= ES58X_FLAG_EFF;
+
+       if (can_is_canfd_skb(skb)) {
+               es58x_flags |= ES58X_FLAG_FD_DATA;
+               if (cf->flags & CANFD_BRS)
+                       es58x_flags |= ES58X_FLAG_FD_BRS;
+               if (cf->flags & CANFD_ESI)
+                       es58x_flags |= ES58X_FLAG_FD_ESI;
+       } else if (cf->can_id & CAN_RTR_FLAG)
+               /* Remote frames are only defined in Classical CAN frames */
+               es58x_flags |= ES58X_FLAG_RTR;
+
+       return es58x_flags;
+}
+
+int es58x_can_get_echo_skb(struct net_device *netdev, u32 packet_idx,
+                          u64 *tstamps, unsigned int pkts);
+int es58x_tx_ack_msg(struct net_device *netdev, u16 tx_free_entries,
+                    enum es58x_ret_u32 rx_cmd_ret_u32);
+int es58x_rx_can_msg(struct net_device *netdev, u64 timestamp, const u8 *data,
+                    canid_t can_id, enum es58x_flag es58x_flags, u8 dlc);
+int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
+                    enum es58x_event event, u64 timestamp);
+void es58x_rx_timestamp(struct es58x_device *es58x_dev, u64 timestamp);
+int es58x_rx_cmd_ret_u8(struct device *dev, enum es58x_ret_type cmd_ret_type,
+                       enum es58x_ret_u8 rx_cmd_ret_u8);
+int es58x_rx_cmd_ret_u32(struct net_device *netdev,
+                        enum es58x_ret_type cmd_ret_type,
+                        enum es58x_ret_u32 rx_cmd_ret_u32);
+int es58x_send_msg(struct es58x_device *es58x_dev, u8 cmd_type, u8 cmd_id,
+                  const void *msg, u16 cmd_len, int channel_idx);
+
+extern const struct es58x_parameters es581_4_param;
+extern const struct es58x_operators es581_4_ops;
+
+extern const struct es58x_parameters es58x_fd_param;
+extern const struct es58x_operators es58x_fd_ops;
+
+#endif /* __ES58X_COMMON_H__ */
diff --git a/drivers/net/can/usb/etas_es58x/es58x_fd.c b/drivers/net/can/usb/etas_es58x/es58x_fd.c
new file mode 100644 (file)
index 0000000..1a2779d
--- /dev/null
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
+ *
+ * File es58x_fd.c: Adds support to ETAS ES582.1 and ES584.1 (naming
+ * convention: we use the term "ES58X FD" when referring to those two
+ * variants together).
+ *
+ * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
+ * Copyright (c) 2020 ETAS K.K.. All rights reserved.
+ * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
+ */
+
+#include <linux/kernel.h>
+#include <asm/unaligned.h>
+
+#include "es58x_core.h"
+#include "es58x_fd.h"
+
+/**
+ * es58x_fd_sizeof_rx_tx_msg() - Calculate the actual length of the
+ *     structure of a rx or tx message.
+ * @msg: message of variable length, must have a dlc and a len fields.
+ *
+ * Even if RTR frames have actually no payload, the ES58X devices
+ * still expect it. Must be a macro in order to accept several types
+ * (struct es58x_fd_tx_can_msg and struct es58x_fd_rx_can_msg) as an
+ * input.
+ *
+ * Return: length of the message.
+ */
+#define es58x_fd_sizeof_rx_tx_msg(msg)                                 \
+({                                                                     \
+       typeof(msg) __msg = (msg);                                      \
+       size_t __msg_len;                                               \
+                                                                       \
+       if (__msg.flags & ES58X_FLAG_FD_DATA)                           \
+               __msg_len = canfd_sanitize_len(__msg.len);              \
+       else                                                            \
+               __msg_len = can_cc_dlc2len(__msg.dlc);                  \
+                                                                       \
+       offsetof(typeof(__msg), data[__msg_len]);                       \
+})
+
+static enum es58x_fd_cmd_type es58x_fd_cmd_type(struct net_device *netdev)
+{
+       u32 ctrlmode = es58x_priv(netdev)->can.ctrlmode;
+
+       if (ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO))
+               return ES58X_FD_CMD_TYPE_CANFD;
+       else
+               return ES58X_FD_CMD_TYPE_CAN;
+}
+
+static u16 es58x_fd_get_msg_len(const union es58x_urb_cmd *urb_cmd)
+{
+       return get_unaligned_le16(&urb_cmd->es58x_fd_urb_cmd.msg_len);
+}
+
+static int es58x_fd_echo_msg(struct net_device *netdev,
+                            const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
+{
+       struct es58x_priv *priv = es58x_priv(netdev);
+       const struct es58x_fd_echo_msg *echo_msg;
+       struct es58x_device *es58x_dev = priv->es58x_dev;
+       u64 *tstamps = es58x_dev->timestamps;
+       u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
+       int i, num_element;
+       u32 rcv_packet_idx;
+
+       const u32 mask = GENMASK(31, sizeof(echo_msg->packet_idx) * 8);
+
+       num_element = es58x_msg_num_element(es58x_dev->dev,
+                                           es58x_fd_urb_cmd->echo_msg,
+                                           msg_len);
+       if (num_element < 0)
+               return num_element;
+       echo_msg = es58x_fd_urb_cmd->echo_msg;
+
+       rcv_packet_idx = (priv->tx_tail & mask) | echo_msg[0].packet_idx;
+       for (i = 0; i < num_element; i++) {
+               if ((u8)rcv_packet_idx != echo_msg[i].packet_idx) {
+                       netdev_err(netdev, "Packet idx jumped from %u to %u\n",
+                                  (u8)rcv_packet_idx - 1,
+                                  echo_msg[i].packet_idx);
+                       return -EBADMSG;
+               }
+
+               tstamps[i] = get_unaligned_le64(&echo_msg[i].timestamp);
+               rcv_packet_idx++;
+       }
+
+       return es58x_can_get_echo_skb(netdev, priv->tx_tail, tstamps, num_element);
+}
+
+static int es58x_fd_rx_can_msg(struct net_device *netdev,
+                              const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
+{
+       struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
+       const u8 *rx_can_msg_buf = es58x_fd_urb_cmd->rx_can_msg_buf;
+       u16 rx_can_msg_buf_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
+       int pkts, ret;
+
+       ret = es58x_check_msg_max_len(es58x_dev->dev,
+                                     es58x_fd_urb_cmd->rx_can_msg_buf,
+                                     rx_can_msg_buf_len);
+       if (ret)
+               return ret;
+
+       for (pkts = 0; rx_can_msg_buf_len > 0; pkts++) {
+               const struct es58x_fd_rx_can_msg *rx_can_msg =
+                   (const struct es58x_fd_rx_can_msg *)rx_can_msg_buf;
+               bool is_can_fd = !!(rx_can_msg->flags & ES58X_FLAG_FD_DATA);
+               /* rx_can_msg_len is the length of the rx_can_msg
+                * buffer. Not to be confused with rx_can_msg->len
+                * which is the length of the CAN payload
+                * rx_can_msg->data.
+                */
+               u16 rx_can_msg_len = es58x_fd_sizeof_rx_tx_msg(*rx_can_msg);
+
+               if (rx_can_msg_len > rx_can_msg_buf_len) {
+                       netdev_err(netdev,
+                                  "%s: Expected a rx_can_msg of size %d but only %d bytes are left in rx_can_msg_buf\n",
+                                  __func__,
+                                  rx_can_msg_len, rx_can_msg_buf_len);
+                       return -EMSGSIZE;
+               }
+               if (rx_can_msg->len > CANFD_MAX_DLEN) {
+                       netdev_err(netdev,
+                                  "%s: Data length is %d but maximum should be %d\n",
+                                  __func__, rx_can_msg->len, CANFD_MAX_DLEN);
+                       return -EMSGSIZE;
+               }
+
+               if (netif_running(netdev)) {
+                       u64 tstamp = get_unaligned_le64(&rx_can_msg->timestamp);
+                       canid_t can_id = get_unaligned_le32(&rx_can_msg->can_id);
+                       u8 dlc;
+
+                       if (is_can_fd)
+                               dlc = can_fd_len2dlc(rx_can_msg->len);
+                       else
+                               dlc = rx_can_msg->dlc;
+
+                       ret = es58x_rx_can_msg(netdev, tstamp, rx_can_msg->data,
+                                              can_id, rx_can_msg->flags, dlc);
+                       if (ret)
+                               break;
+               }
+
+               rx_can_msg_buf_len -= rx_can_msg_len;
+               rx_can_msg_buf += rx_can_msg_len;
+       }
+
+       if (!netif_running(netdev)) {
+               if (net_ratelimit())
+                       netdev_info(netdev,
+                                   "%s: %s is down, dropping %d rx packets\n",
+                                   __func__, netdev->name, pkts);
+               netdev->stats.rx_dropped += pkts;
+       }
+
+       return ret;
+}
+
+static int es58x_fd_rx_event_msg(struct net_device *netdev,
+                                const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
+{
+       struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
+       u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
+       const struct es58x_fd_rx_event_msg *rx_event_msg;
+       int ret;
+
+       ret = es58x_check_msg_len(es58x_dev->dev, *rx_event_msg, msg_len);
+       if (ret)
+               return ret;
+
+       rx_event_msg = &es58x_fd_urb_cmd->rx_event_msg;
+
+       return es58x_rx_err_msg(netdev, rx_event_msg->error_code,
+                               rx_event_msg->event_code,
+                               get_unaligned_le64(&rx_event_msg->timestamp));
+}
+
+static int es58x_fd_rx_cmd_ret_u32(struct net_device *netdev,
+                                  const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd,
+                                  enum es58x_ret_type cmd_ret_type)
+{
+       struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
+       u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
+       int ret;
+
+       ret = es58x_check_msg_len(es58x_dev->dev,
+                                 es58x_fd_urb_cmd->rx_cmd_ret_le32, msg_len);
+       if (ret)
+               return ret;
+
+       return es58x_rx_cmd_ret_u32(netdev, cmd_ret_type,
+                                   get_unaligned_le32(&es58x_fd_urb_cmd->rx_cmd_ret_le32));
+}
+
+static int es58x_fd_tx_ack_msg(struct net_device *netdev,
+                              const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
+{
+       struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
+       const struct es58x_fd_tx_ack_msg *tx_ack_msg;
+       u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
+       int ret;
+
+       tx_ack_msg = &es58x_fd_urb_cmd->tx_ack_msg;
+       ret = es58x_check_msg_len(es58x_dev->dev, *tx_ack_msg, msg_len);
+       if (ret)
+               return ret;
+
+       return es58x_tx_ack_msg(netdev,
+                               get_unaligned_le16(&tx_ack_msg->tx_free_entries),
+                               get_unaligned_le32(&tx_ack_msg->rx_cmd_ret_le32));
+}
+
+static int es58x_fd_can_cmd_id(struct es58x_device *es58x_dev,
+                              const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
+{
+       struct net_device *netdev;
+       int ret;
+
+       ret = es58x_get_netdev(es58x_dev, es58x_fd_urb_cmd->channel_idx,
+                              ES58X_FD_CHANNEL_IDX_OFFSET, &netdev);
+       if (ret)
+               return ret;
+
+       switch ((enum es58x_fd_can_cmd_id)es58x_fd_urb_cmd->cmd_id) {
+       case ES58X_FD_CAN_CMD_ID_ENABLE_CHANNEL:
+               return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,
+                                              ES58X_RET_TYPE_ENABLE_CHANNEL);
+
+       case ES58X_FD_CAN_CMD_ID_DISABLE_CHANNEL:
+               return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,
+                                              ES58X_RET_TYPE_DISABLE_CHANNEL);
+
+       case ES58X_FD_CAN_CMD_ID_TX_MSG:
+               return es58x_fd_tx_ack_msg(netdev, es58x_fd_urb_cmd);
+
+       case ES58X_FD_CAN_CMD_ID_ECHO_MSG:
+               return es58x_fd_echo_msg(netdev, es58x_fd_urb_cmd);
+
+       case ES58X_FD_CAN_CMD_ID_RX_MSG:
+               return es58x_fd_rx_can_msg(netdev, es58x_fd_urb_cmd);
+
+       case ES58X_FD_CAN_CMD_ID_RESET_RX:
+               return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,
+                                              ES58X_RET_TYPE_RESET_RX);
+
+       case ES58X_FD_CAN_CMD_ID_RESET_TX:
+               return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,
+                                              ES58X_RET_TYPE_RESET_TX);
+
+       case ES58X_FD_CAN_CMD_ID_ERROR_OR_EVENT_MSG:
+               return es58x_fd_rx_event_msg(netdev, es58x_fd_urb_cmd);
+
+       default:
+               return -EBADRQC;
+       }
+}
+
+static int es58x_fd_device_cmd_id(struct es58x_device *es58x_dev,
+                                 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
+{
+       u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
+       int ret;
+
+       switch ((enum es58x_fd_dev_cmd_id)es58x_fd_urb_cmd->cmd_id) {
+       case ES58X_FD_DEV_CMD_ID_TIMESTAMP:
+               ret = es58x_check_msg_len(es58x_dev->dev,
+                                         es58x_fd_urb_cmd->timestamp, msg_len);
+               if (ret)
+                       return ret;
+               es58x_rx_timestamp(es58x_dev,
+                                  get_unaligned_le64(&es58x_fd_urb_cmd->timestamp));
+               return 0;
+
+       default:
+               return -EBADRQC;
+       }
+}
+
+static int es58x_fd_handle_urb_cmd(struct es58x_device *es58x_dev,
+                                  const union es58x_urb_cmd *urb_cmd)
+{
+       const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd;
+       int ret;
+
+       es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;
+
+       switch ((enum es58x_fd_cmd_type)es58x_fd_urb_cmd->cmd_type) {
+       case ES58X_FD_CMD_TYPE_CAN:
+       case ES58X_FD_CMD_TYPE_CANFD:
+               ret = es58x_fd_can_cmd_id(es58x_dev, es58x_fd_urb_cmd);
+               break;
+
+       case ES58X_FD_CMD_TYPE_DEVICE:
+               ret = es58x_fd_device_cmd_id(es58x_dev, es58x_fd_urb_cmd);
+               break;
+
+       default:
+               ret = -EBADRQC;
+               break;
+       }
+
+       if (ret == -EBADRQC)
+               dev_err(es58x_dev->dev,
+                       "%s: Unknown command type (0x%02X) and command ID (0x%02X) combination\n",
+                       __func__, es58x_fd_urb_cmd->cmd_type,
+                       es58x_fd_urb_cmd->cmd_id);
+
+       return ret;
+}
+
+static void es58x_fd_fill_urb_header(union es58x_urb_cmd *urb_cmd, u8 cmd_type,
+                                    u8 cmd_id, u8 channel_idx, u16 msg_len)
+{
+       struct es58x_fd_urb_cmd *es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;
+
+       es58x_fd_urb_cmd->SOF = cpu_to_le16(es58x_fd_param.tx_start_of_frame);
+       es58x_fd_urb_cmd->cmd_type = cmd_type;
+       es58x_fd_urb_cmd->cmd_id = cmd_id;
+       es58x_fd_urb_cmd->channel_idx = channel_idx;
+       es58x_fd_urb_cmd->msg_len = cpu_to_le16(msg_len);
+}
+
+static int es58x_fd_tx_can_msg(struct es58x_priv *priv,
+                              const struct sk_buff *skb)
+{
+       struct es58x_device *es58x_dev = priv->es58x_dev;
+       union es58x_urb_cmd *urb_cmd = priv->tx_urb->transfer_buffer;
+       struct es58x_fd_urb_cmd *es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;
+       struct can_frame *cf = (struct can_frame *)skb->data;
+       struct es58x_fd_tx_can_msg *tx_can_msg;
+       bool is_fd = can_is_canfd_skb(skb);
+       u16 msg_len;
+       int ret;
+
+       if (priv->tx_can_msg_cnt == 0) {
+               msg_len = 0;
+               es58x_fd_fill_urb_header(urb_cmd,
+                                        is_fd ? ES58X_FD_CMD_TYPE_CANFD
+                                              : ES58X_FD_CMD_TYPE_CAN,
+                                        ES58X_FD_CAN_CMD_ID_TX_MSG_NO_ACK,
+                                        priv->channel_idx, msg_len);
+       } else {
+               msg_len = es58x_fd_get_msg_len(urb_cmd);
+       }
+
+       ret = es58x_check_msg_max_len(es58x_dev->dev,
+                                     es58x_fd_urb_cmd->tx_can_msg_buf,
+                                     msg_len + sizeof(*tx_can_msg));
+       if (ret)
+               return ret;
+
+       /* Fill message contents. */
+       tx_can_msg = (struct es58x_fd_tx_can_msg *)
+           &es58x_fd_urb_cmd->tx_can_msg_buf[msg_len];
+       tx_can_msg->packet_idx = (u8)priv->tx_head;
+       put_unaligned_le32(es58x_get_raw_can_id(cf), &tx_can_msg->can_id);
+       tx_can_msg->flags = (u8)es58x_get_flags(skb);
+       if (is_fd)
+               tx_can_msg->len = cf->len;
+       else
+               tx_can_msg->dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
+       memcpy(tx_can_msg->data, cf->data, cf->len);
+
+       /* Calculate new sizes */
+       msg_len += es58x_fd_sizeof_rx_tx_msg(*tx_can_msg);
+       priv->tx_urb->transfer_buffer_length = es58x_get_urb_cmd_len(es58x_dev,
+                                                                    msg_len);
+       put_unaligned_le16(msg_len, &es58x_fd_urb_cmd->msg_len);
+
+       return 0;
+}
+
+static void es58x_fd_convert_bittiming(struct es58x_fd_bittiming *es58x_fd_bt,
+                                      struct can_bittiming *bt)
+{
+       /* The actual value set in the hardware registers is one less
+        * than the functional value.
+        */
+       const int offset = 1;
+
+       es58x_fd_bt->bitrate = cpu_to_le32(bt->bitrate);
+       es58x_fd_bt->tseg1 =
+           cpu_to_le16(bt->prop_seg + bt->phase_seg1 - offset);
+       es58x_fd_bt->tseg2 = cpu_to_le16(bt->phase_seg2 - offset);
+       es58x_fd_bt->brp = cpu_to_le16(bt->brp - offset);
+       es58x_fd_bt->sjw = cpu_to_le16(bt->sjw - offset);
+}
+
+static int es58x_fd_enable_channel(struct es58x_priv *priv)
+{
+       struct es58x_device *es58x_dev = priv->es58x_dev;
+       struct net_device *netdev = es58x_dev->netdev[priv->channel_idx];
+       struct es58x_fd_tx_conf_msg tx_conf_msg = { 0 };
+       u32 ctrlmode;
+       size_t conf_len = 0;
+
+       es58x_fd_convert_bittiming(&tx_conf_msg.nominal_bittiming,
+                                  &priv->can.bittiming);
+       ctrlmode = priv->can.ctrlmode;
+
+       if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+               tx_conf_msg.samples_per_bit = ES58X_SAMPLES_PER_BIT_THREE;
+       else
+               tx_conf_msg.samples_per_bit = ES58X_SAMPLES_PER_BIT_ONE;
+       tx_conf_msg.sync_edge = ES58X_SYNC_EDGE_SINGLE;
+       tx_conf_msg.physical_layer = ES58X_PHYSICAL_LAYER_HIGH_SPEED;
+       tx_conf_msg.echo_mode = ES58X_ECHO_ON;
+       if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
+               tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_PASSIVE;
+       else
+               tx_conf_msg.ctrlmode |=  ES58X_FD_CTRLMODE_ACTIVE;
+
+       if (ctrlmode & CAN_CTRLMODE_FD_NON_ISO) {
+               tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_FD_NON_ISO;
+               tx_conf_msg.canfd_enabled = 1;
+       } else if (ctrlmode & CAN_CTRLMODE_FD) {
+               tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_FD;
+               tx_conf_msg.canfd_enabled = 1;
+       }
+
+       if (tx_conf_msg.canfd_enabled) {
+               es58x_fd_convert_bittiming(&tx_conf_msg.data_bittiming,
+                                          &priv->can.data_bittiming);
+
+               if (priv->can.tdc.tdco) {
+                       tx_conf_msg.tdc_enabled = 1;
+                       tx_conf_msg.tdco = cpu_to_le16(priv->can.tdc.tdco);
+                       tx_conf_msg.tdcf = cpu_to_le16(priv->can.tdc.tdcf);
+               }
+
+               conf_len = ES58X_FD_CANFD_CONF_LEN;
+       } else {
+               conf_len = ES58X_FD_CAN_CONF_LEN;
+       }
+
+       return es58x_send_msg(es58x_dev, es58x_fd_cmd_type(netdev),
+                             ES58X_FD_CAN_CMD_ID_ENABLE_CHANNEL,
+                             &tx_conf_msg, conf_len, priv->channel_idx);
+}
+
+static int es58x_fd_disable_channel(struct es58x_priv *priv)
+{
+       /* The type (ES58X_FD_CMD_TYPE_CAN or ES58X_FD_CMD_TYPE_CANFD) does
+        * not matter here.
+        */
+       return es58x_send_msg(priv->es58x_dev, ES58X_FD_CMD_TYPE_CAN,
+                             ES58X_FD_CAN_CMD_ID_DISABLE_CHANNEL,
+                             ES58X_EMPTY_MSG, 0, priv->channel_idx);
+}
+
+static int es58x_fd_get_timestamp(struct es58x_device *es58x_dev)
+{
+       return es58x_send_msg(es58x_dev, ES58X_FD_CMD_TYPE_DEVICE,
+                             ES58X_FD_DEV_CMD_ID_TIMESTAMP, ES58X_EMPTY_MSG,
+                             0, ES58X_CHANNEL_IDX_NA);
+}
+
+/* Nominal bittiming constants for ES582.1 and ES584.1 as specified in
+ * the microcontroller datasheet: "SAM E701/S70/V70/V71 Family"
+ * section 49.6.8 "MCAN Nominal Bit Timing and Prescaler Register"
+ * from Microchip.
+ *
+ * The values from the specification are the hardware register
+ * values. To convert them to the functional values, all ranges were
+ * incremented by 1 (e.g. range [0..n-1] changed to [1..n]).
+ */
+static const struct can_bittiming_const es58x_fd_nom_bittiming_const = {
+       .name = "ES582.1/ES584.1",
+       .tseg1_min = 2,
+       .tseg1_max = 256,
+       .tseg2_min = 2,
+       .tseg2_max = 128,
+       .sjw_max = 128,
+       .brp_min = 1,
+       .brp_max = 512,
+       .brp_inc = 1
+};
+
+/* Data bittiming constants for ES582.1 and ES584.1 as specified in
+ * the microcontroller datasheet: "SAM E701/S70/V70/V71 Family"
+ * section 49.6.4 "MCAN Data Bit Timing and Prescaler Register" from
+ * Microchip.
+ */
+static const struct can_bittiming_const es58x_fd_data_bittiming_const = {
+       .name = "ES582.1/ES584.1",
+       .tseg1_min = 2,
+       .tseg1_max = 32,
+       .tseg2_min = 1,
+       .tseg2_max = 16,
+       .sjw_max = 8,
+       .brp_min = 1,
+       .brp_max = 32,
+       .brp_inc = 1
+};
+
+/* Transmission Delay Compensation constants for ES582.1 and ES584.1
+ * as specified in the microcontroller datasheet: "SAM
+ * E701/S70/V70/V71 Family" section 49.6.15 "MCAN Transmitter Delay
+ * Compensation Register" from Microchip.
+ */
+static const struct can_tdc_const es58x_tdc_const = {
+       .tdcv_max = 0, /* Manual mode not supported. */
+       .tdco_max = 127,
+       .tdcf_max = 127
+};
+
+const struct es58x_parameters es58x_fd_param = {
+       .bittiming_const = &es58x_fd_nom_bittiming_const,
+       .data_bittiming_const = &es58x_fd_data_bittiming_const,
+       .tdc_const = &es58x_tdc_const,
+       /* The devices use NXP TJA1044G transievers which guarantee
+        * the timing for data rates up to 5 Mbps. Bitrates up to 8
+        * Mbps work in an optimal environment but are not recommended
+        * for production environment.
+        */
+       .bitrate_max = 8 * CAN_MBPS,
+       .clock = {.freq = 80 * CAN_MHZ},
+       .ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY |
+           CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO |
+           CAN_CTRLMODE_CC_LEN8_DLC,
+       .tx_start_of_frame = 0xCEFA,    /* FACE in little endian */
+       .rx_start_of_frame = 0xFECA,    /* CAFE in little endian */
+       .tx_urb_cmd_max_len = ES58X_FD_TX_URB_CMD_MAX_LEN,
+       .rx_urb_cmd_max_len = ES58X_FD_RX_URB_CMD_MAX_LEN,
+       /* Size of internal device TX queue is 500.
+        *
+        * However, when reaching value around 278, the device's busy
+        * LED turns on and thus maximum value of 500 is never reached
+        * in practice. Also, when this value is too high, some error
+        * on the echo_msg were witnessed when the device is
+        * recovering from bus off.
+        *
+        * For above reasons, a value that would prevent the device
+        * from becoming busy was chosen. In practice, BQL would
+        * prevent the value from even getting closer to below
+        * maximum, so no impact on performance was measured.
+        */
+       .fifo_mask = 255, /* echo_skb_max = 256 */
+       .dql_min_limit = CAN_FRAME_LEN_MAX * 15, /* Empirical value. */
+       .tx_bulk_max = ES58X_FD_TX_BULK_MAX,
+       .urb_cmd_header_len = ES58X_FD_URB_CMD_HEADER_LEN,
+       .rx_urb_max = ES58X_RX_URBS_MAX,
+       .tx_urb_max = ES58X_TX_URBS_MAX
+};
+
+const struct es58x_operators es58x_fd_ops = {
+       .get_msg_len = es58x_fd_get_msg_len,
+       .handle_urb_cmd = es58x_fd_handle_urb_cmd,
+       .fill_urb_header = es58x_fd_fill_urb_header,
+       .tx_can_msg = es58x_fd_tx_can_msg,
+       .enable_channel = es58x_fd_enable_channel,
+       .disable_channel = es58x_fd_disable_channel,
+       .reset_device = NULL, /* Not implemented in the device firmware. */
+       .get_timestamp = es58x_fd_get_timestamp
+};
diff --git a/drivers/net/can/usb/etas_es58x/es58x_fd.h b/drivers/net/can/usb/etas_es58x/es58x_fd.h
new file mode 100644 (file)
index 0000000..ee18a87
--- /dev/null
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
+ *
+ * File es58x_fd.h: Definitions and declarations specific to ETAS
+ * ES582.1 and ES584.1 (naming convention: we use the term "ES58X FD"
+ * when referring to those two variants together).
+ *
+ * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
+ * Copyright (c) 2020 ETAS K.K.. All rights reserved.
+ * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
+ */
+
+#ifndef __ES58X_FD_H__
+#define __ES58X_FD_H__
+
+#include <linux/types.h>
+
+#define ES582_1_NUM_CAN_CH 2
+#define ES584_1_NUM_CAN_CH 1
+#define ES58X_FD_NUM_CAN_CH 2
+#define ES58X_FD_CHANNEL_IDX_OFFSET 0
+
+#define ES58X_FD_TX_BULK_MAX 100
+#define ES58X_FD_RX_BULK_MAX 100
+#define ES58X_FD_ECHO_BULK_MAX 100
+
+enum es58x_fd_cmd_type {
+       ES58X_FD_CMD_TYPE_CAN = 0x03,
+       ES58X_FD_CMD_TYPE_CANFD = 0x04,
+       ES58X_FD_CMD_TYPE_DEVICE = 0xFF
+};
+
+/* Command IDs for ES58X_FD_CMD_TYPE_{CAN,CANFD}. */
+enum es58x_fd_can_cmd_id {
+       ES58X_FD_CAN_CMD_ID_ENABLE_CHANNEL = 0x01,
+       ES58X_FD_CAN_CMD_ID_DISABLE_CHANNEL = 0x02,
+       ES58X_FD_CAN_CMD_ID_TX_MSG = 0x05,
+       ES58X_FD_CAN_CMD_ID_ECHO_MSG = 0x07,
+       ES58X_FD_CAN_CMD_ID_RX_MSG = 0x10,
+       ES58X_FD_CAN_CMD_ID_ERROR_OR_EVENT_MSG = 0x11,
+       ES58X_FD_CAN_CMD_ID_RESET_RX = 0x20,
+       ES58X_FD_CAN_CMD_ID_RESET_TX = 0x21,
+       ES58X_FD_CAN_CMD_ID_TX_MSG_NO_ACK = 0x55
+};
+
+/* Command IDs for ES58X_FD_CMD_TYPE_DEVICE. */
+enum es58x_fd_dev_cmd_id {
+       ES58X_FD_DEV_CMD_ID_GETTIMETICKS = 0x01,
+       ES58X_FD_DEV_CMD_ID_TIMESTAMP = 0x02
+};
+
+/**
+ * enum es58x_fd_ctrlmode - Controller mode.
+ * @ES58X_FD_CTRLMODE_ACTIVE: send and receive messages.
+ * @ES58X_FD_CTRLMODE_PASSIVE: only receive messages (monitor). Do not
+ *     send anything, not even the acknowledgment bit.
+ * @ES58X_FD_CTRLMODE_FD: CAN FD according to ISO11898-1.
+ * @ES58X_FD_CTRLMODE_FD_NON_ISO: follow Bosch CAN FD Specification
+ *     V1.0
+ * @ES58X_FD_CTRLMODE_DISABLE_PROTOCOL_EXCEPTION_HANDLING: How to
+ *     behave when CAN FD reserved bit is monitored as
+ *     dominant. (c.f. ISO 11898-1:2015, section 10.4.2.4 "Control
+ *     field", paragraph "r0 bit"). 0 (not disable = enable): send
+ *     error frame. 1 (disable): goes into bus integration mode
+ *     (c.f. below).
+ * @ES58X_FD_CTRLMODE_EDGE_FILTER_DURING_BUS_INTEGRATION: 0: Edge
+ *     filtering is disabled. 1: Edge filtering is enabled. Two
+ *     consecutive dominant bits required to detect an edge for hard
+ *     synchronization.
+ */
+enum es58x_fd_ctrlmode {
+       ES58X_FD_CTRLMODE_ACTIVE = 0,
+       ES58X_FD_CTRLMODE_PASSIVE = BIT(0),
+       ES58X_FD_CTRLMODE_FD = BIT(4),
+       ES58X_FD_CTRLMODE_FD_NON_ISO = BIT(5),
+       ES58X_FD_CTRLMODE_DISABLE_PROTOCOL_EXCEPTION_HANDLING = BIT(6),
+       ES58X_FD_CTRLMODE_EDGE_FILTER_DURING_BUS_INTEGRATION = BIT(7)
+};
+
+struct es58x_fd_bittiming {
+       __le32 bitrate;
+       __le16 tseg1;           /* range: [tseg1_min-1..tseg1_max-1] */
+       __le16 tseg2;           /* range: [tseg2_min-1..tseg2_max-1] */
+       __le16 brp;             /* range: [brp_min-1..brp_max-1] */
+       __le16 sjw;             /* range: [0..sjw_max-1] */
+} __packed;
+
+/**
+ * struct es58x_fd_tx_conf_msg - Channel configuration.
+ * @nominal_bittiming: Nominal bittiming.
+ * @samples_per_bit: type enum es58x_samples_per_bit.
+ * @sync_edge: type enum es58x_sync_edge.
+ * @physical_layer: type enum es58x_physical_layer.
+ * @echo_mode: type enum es58x_echo_mode.
+ * @ctrlmode: type enum es58x_fd_ctrlmode.
+ * @canfd_enabled: boolean (0: Classical CAN, 1: CAN and/or CANFD).
+ * @data_bittiming: Bittiming for flexible data-rate transmission.
+ * @tdc_enabled: Transmitter Delay Compensation switch (0: disabled,
+ *     1: enabled). On very high bitrates, the delay between when the
+ *     bit is sent and received on the CANTX and CANRX pins of the
+ *     transceiver start to be significant enough for errors to occur
+ *     and thus need to be compensated.
+ * @tdco: Transmitter Delay Compensation Offset. Offset value, in time
+ *     quanta, defining the delay between the start of the bit
+ *     reception on the CANRX pin of the transceiver and the SSP
+ *     (Secondary Sample Point). Valid values: 0 to 127.
+ * @tdcf: Transmitter Delay Compensation Filter window. Defines the
+ *     minimum value for the SSP position, in time quanta. The
+ *     feature is enabled when TDCF is configured to a value greater
+ *     than TDCO. Valid values: 0 to 127.
+ *
+ * Please refer to the microcontroller datasheet: "SAM
+ * E701/S70/V70/V71 Family" section 49 "Controller Area Network
+ * (MCAN)" for additional information.
+ */
+struct es58x_fd_tx_conf_msg {
+       struct es58x_fd_bittiming nominal_bittiming;
+       u8 samples_per_bit;
+       u8 sync_edge;
+       u8 physical_layer;
+       u8 echo_mode;
+       u8 ctrlmode;
+       u8 canfd_enabled;
+       struct es58x_fd_bittiming data_bittiming;
+       u8 tdc_enabled;
+       __le16 tdco;
+       __le16 tdcf;
+} __packed;
+
+#define ES58X_FD_CAN_CONF_LEN                                  \
+       (offsetof(struct es58x_fd_tx_conf_msg, canfd_enabled))
+#define ES58X_FD_CANFD_CONF_LEN (sizeof(struct es58x_fd_tx_conf_msg))
+
+struct es58x_fd_tx_can_msg {
+       u8 packet_idx;
+       __le32 can_id;
+       u8 flags;
+       union {
+               u8 dlc;         /* Only if cmd_id is ES58X_FD_CMD_TYPE_CAN */
+               u8 len;         /* Only if cmd_id is ES58X_FD_CMD_TYPE_CANFD */
+       } __packed;
+       u8 data[CANFD_MAX_DLEN];
+} __packed;
+
+#define ES58X_FD_CAN_TX_LEN                                            \
+       (offsetof(struct es58x_fd_tx_can_msg, data[CAN_MAX_DLEN]))
+#define ES58X_FD_CANFD_TX_LEN (sizeof(struct es58x_fd_tx_can_msg))
+
+struct es58x_fd_rx_can_msg {
+       __le64 timestamp;
+       __le32 can_id;
+       u8 flags;
+       union {
+               u8 dlc;         /* Only if cmd_id is ES58X_FD_CMD_TYPE_CAN */
+               u8 len;         /* Only if cmd_id is ES58X_FD_CMD_TYPE_CANFD */
+       } __packed;
+       u8 data[CANFD_MAX_DLEN];
+} __packed;
+
+#define ES58X_FD_CAN_RX_LEN                                            \
+       (offsetof(struct es58x_fd_rx_can_msg, data[CAN_MAX_DLEN]))
+#define ES58X_FD_CANFD_RX_LEN (sizeof(struct es58x_fd_rx_can_msg))
+
+struct es58x_fd_echo_msg {
+       __le64 timestamp;
+       u8 packet_idx;
+} __packed;
+
+struct es58x_fd_rx_event_msg {
+       __le64 timestamp;
+       __le32 can_id;
+       u8 flags;               /* type enum es58x_flag */
+       u8 error_type;          /* 0: event, 1: error */
+       u8 error_code;
+       u8 event_code;
+} __packed;
+
+struct es58x_fd_tx_ack_msg {
+       __le32 rx_cmd_ret_le32; /* type enum es58x_cmd_ret_code_u32 */
+       __le16 tx_free_entries; /* Number of remaining free entries in the device TX queue */
+} __packed;
+
+/**
+ * struct es58x_fd_urb_cmd - Commands received from or sent to the
+ *     ES58X FD device.
+ * @SOF: Start of Frame.
+ * @cmd_type: Command Type (type: enum es58x_fd_cmd_type). The CRC
+ *     calculation starts at this position.
+ * @cmd_id: Command ID (type: enum es58x_fd_cmd_id).
+ * @channel_idx: Channel index starting at 0.
+ * @msg_len: Length of the message, excluding CRC (i.e. length of the
+ *     union).
+ * @tx_conf_msg: Channel configuration.
+ * @tx_can_msg_buf: Concatenation of Tx messages. Type is "u8[]"
+ *     instead of "struct es58x_fd_tx_msg[]" because the structure
+ *     has a flexible size.
+ * @rx_can_msg_buf: Concatenation Rx messages. Type is "u8[]" instead
+ *     of "struct es58x_fd_rx_msg[]" because the structure has a
+ *     flexible size.
+ * @echo_msg: Array of echo messages (e.g. Tx messages being looped
+ *     back).
+ * @rx_event_msg: Error or event message.
+ * @tx_ack_msg: Tx acknowledgment message.
+ * @timestamp: Timestamp reply.
+ * @rx_cmd_ret_le32: Rx 32 bits return code (type: enum
+ *     es58x_cmd_ret_code_u32).
+ * @raw_msg: Message raw payload.
+ * @reserved_for_crc16_do_not_use: The structure ends with a
+ *     CRC16. Because the structures in above union are of variable
+ *     lengths, we can not predict the offset of the CRC in
+ *     advance. Use functions es58x_get_crc() and es58x_set_crc() to
+ *     manipulate it.
+ */
+struct es58x_fd_urb_cmd {
+       __le16 SOF;
+       u8 cmd_type;
+       u8 cmd_id;
+       u8 channel_idx;
+       __le16 msg_len;
+
+       union {
+               struct es58x_fd_tx_conf_msg tx_conf_msg;
+               u8 tx_can_msg_buf[ES58X_FD_TX_BULK_MAX * ES58X_FD_CANFD_TX_LEN];
+               u8 rx_can_msg_buf[ES58X_FD_RX_BULK_MAX * ES58X_FD_CANFD_RX_LEN];
+               struct es58x_fd_echo_msg echo_msg[ES58X_FD_ECHO_BULK_MAX];
+               struct es58x_fd_rx_event_msg rx_event_msg;
+               struct es58x_fd_tx_ack_msg tx_ack_msg;
+               __le64 timestamp;
+               __le32 rx_cmd_ret_le32;
+               u8 raw_msg[0];
+       } __packed;
+
+       __le16 reserved_for_crc16_do_not_use;
+} __packed;
+
+#define ES58X_FD_URB_CMD_HEADER_LEN (offsetof(struct es58x_fd_urb_cmd, raw_msg))
+#define ES58X_FD_TX_URB_CMD_MAX_LEN                                    \
+       ES58X_SIZEOF_URB_CMD(struct es58x_fd_urb_cmd, tx_can_msg_buf)
+#define ES58X_FD_RX_URB_CMD_MAX_LEN                                    \
+       ES58X_SIZEOF_URB_CMD(struct es58x_fd_urb_cmd, rx_can_msg_buf)
+
+#endif /* __ES58X_FD_H__ */
index ba509ae..1d6f772 100644 (file)
@@ -365,16 +365,11 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
        int err;
 
        err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_SN, PCAN_USB_GET, args);
-       if (err) {
-               netdev_err(dev->netdev, "getting serial failure: %d\n", err);
-       } else if (serial_number) {
-               __le32 tmp32;
-
-               memcpy(&tmp32, args, 4);
-               *serial_number = le32_to_cpu(tmp32);
-       }
+       if (err)
+               return err;
+       *serial_number = le32_to_cpup((__le32 *)args);
 
-       return err;
+       return 0;
 }
 
 /*
@@ -388,8 +383,8 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
        err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args);
        if (err)
                netdev_err(dev->netdev, "getting device id failure: %d\n", err);
-       else if (device_id)
-               *device_id = args[0];
+
+       *device_id = args[0];
 
        return err;
 }
@@ -399,14 +394,10 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
  */
 static int pcan_usb_update_ts(struct pcan_usb_msg_context *mc)
 {
-       __le16 tmp16;
-
-       if ((mc->ptr+2) > mc->end)
+       if ((mc->ptr + 2) > mc->end)
                return -EINVAL;
 
-       memcpy(&tmp16, mc->ptr, 2);
-
-       mc->ts16 = le16_to_cpu(tmp16);
+       mc->ts16 = get_unaligned_le16(mc->ptr);
 
        if (mc->rec_idx > 0)
                peak_usb_update_ts_now(&mc->pdev->time_ref, mc->ts16);
@@ -423,16 +414,13 @@ static int pcan_usb_decode_ts(struct pcan_usb_msg_context *mc, u8 first_packet)
 {
        /* only 1st packet supplies a word timestamp */
        if (first_packet) {
-               __le16 tmp16;
-
                if ((mc->ptr + 2) > mc->end)
                        return -EINVAL;
 
-               memcpy(&tmp16, mc->ptr, 2);
-               mc->ptr += 2;
-
-               mc->ts16 = le16_to_cpu(tmp16);
+               mc->ts16 = get_unaligned_le16(mc->ptr);
                mc->prev_ts8 = mc->ts16 & 0x00ff;
+
+               mc->ptr += 2;
        } else {
                u8 ts8;
 
@@ -722,25 +710,17 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
                return -ENOMEM;
 
        if (status_len & PCAN_USB_STATUSLEN_EXT_ID) {
-               __le32 tmp32;
-
                if ((mc->ptr + 4) > mc->end)
                        goto decode_failed;
 
-               memcpy(&tmp32, mc->ptr, 4);
+               cf->can_id = get_unaligned_le32(mc->ptr) >> 3 | CAN_EFF_FLAG;
                mc->ptr += 4;
-
-               cf->can_id = (le32_to_cpu(tmp32) >> 3) | CAN_EFF_FLAG;
        } else {
-               __le16 tmp16;
-
                if ((mc->ptr + 2) > mc->end)
                        goto decode_failed;
 
-               memcpy(&tmp16, mc->ptr, 2);
+               cf->can_id = get_unaligned_le16(mc->ptr) >> 5;
                mc->ptr += 2;
-
-               cf->can_id = le16_to_cpu(tmp16) >> 5;
        }
 
        can_frame_set_cc_len(cf, rec_len, mc->pdev->dev.can.ctrlmode);
@@ -854,15 +834,15 @@ static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb,
 
        /* can id */
        if (cf->can_id & CAN_EFF_FLAG) {
-               __le32 tmp32 = cpu_to_le32((cf->can_id & CAN_ERR_MASK) << 3);
-
                *pc |= PCAN_USB_STATUSLEN_EXT_ID;
-               memcpy(++pc, &tmp32, 4);
+               pc++;
+
+               put_unaligned_le32((cf->can_id & CAN_ERR_MASK) << 3, pc);
                pc += 4;
        } else {
-               __le16 tmp16 = cpu_to_le16((cf->can_id & CAN_ERR_MASK) << 5);
+               pc++;
 
-               memcpy(++pc, &tmp16, 2);
+               put_unaligned_le16((cf->can_id & CAN_ERR_MASK) << 5, pc);
                pc += 2;
        }
 
@@ -1039,7 +1019,7 @@ const struct peak_usb_adapter pcan_usb = {
                              CAN_CTRLMODE_BERR_REPORTING |
                              CAN_CTRLMODE_CC_LEN8_DLC,
        .clock = {
-               .freq = PCAN_USB_CRYSTAL_HZ / 2 ,
+               .freq = PCAN_USB_CRYSTAL_HZ / 2,
        },
        .bittiming_const = &pcan_usb_const,
 
@@ -1050,7 +1030,6 @@ const struct peak_usb_adapter pcan_usb = {
 
        /* timestamps usage */
        .ts_used_bits = 16,
-       .ts_period = 24575, /* calibration period in ts. */
        .us_per_ts_scale = PCAN_USB_TS_US_PER_TICK, /* us=(ts*scale) */
        .us_per_ts_shift = PCAN_USB_TS_DIV_SHIFTER, /*  >> shift     */
 
index e69b005..e8f43ed 100644 (file)
@@ -27,28 +27,32 @@ MODULE_DESCRIPTION("CAN driver for PEAK-System USB adapters");
 MODULE_LICENSE("GPL v2");
 
 /* Table of devices that work with this driver */
-static struct usb_device_id peak_usb_table[] = {
-       {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID)},
-       {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)},
-       {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBFD_PRODUCT_ID)},
-       {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPROFD_PRODUCT_ID)},
-       {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBCHIP_PRODUCT_ID)},
-       {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBX6_PRODUCT_ID)},
-       {} /* Terminating entry */
+static const struct usb_device_id peak_usb_table[] = {
+       {
+               USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&pcan_usb,
+       }, {
+               USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&pcan_usb_pro,
+       }, {
+               USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBFD_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&pcan_usb_fd,
+       }, {
+               USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPROFD_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&pcan_usb_pro_fd,
+       }, {
+               USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBCHIP_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&pcan_usb_chip,
+       }, {
+               USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBX6_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&pcan_usb_x6,
+       }, {
+               /* Terminating entry */
+       }
 };
 
 MODULE_DEVICE_TABLE(usb, peak_usb_table);
 
-/* List of supported PCAN-USB adapters (NULL terminated list) */
-static const struct peak_usb_adapter *const peak_usb_adapters_list[] = {
-       &pcan_usb,
-       &pcan_usb_pro,
-       &pcan_usb_fd,
-       &pcan_usb_pro_fd,
-       &pcan_usb_chip,
-       &pcan_usb_x6,
-};
-
 /*
  * dump memory
  */
@@ -624,6 +628,7 @@ static int peak_usb_ndo_stop(struct net_device *netdev)
        /* can set bus off now */
        if (dev->adapter->dev_set_bus) {
                int err = dev->adapter->dev_set_bus(dev, 0);
+
                if (err)
                        return err;
        }
@@ -927,24 +932,11 @@ static void peak_usb_disconnect(struct usb_interface *intf)
 static int peak_usb_probe(struct usb_interface *intf,
                          const struct usb_device_id *id)
 {
-       struct usb_device *usb_dev = interface_to_usbdev(intf);
-       const u16 usb_id_product = le16_to_cpu(usb_dev->descriptor.idProduct);
-       const struct peak_usb_adapter *peak_usb_adapter = NULL;
+       const struct peak_usb_adapter *peak_usb_adapter;
        int i, err = -ENOMEM;
 
        /* get corresponding PCAN-USB adapter */
-       for (i = 0; i < ARRAY_SIZE(peak_usb_adapters_list); i++)
-               if (peak_usb_adapters_list[i]->device_id == usb_id_product) {
-                       peak_usb_adapter = peak_usb_adapters_list[i];
-                       break;
-               }
-
-       if (!peak_usb_adapter) {
-               /* should never come except device_id bad usage in this file */
-               pr_err("%s: didn't find device id. 0x%x in devices list\n",
-                       PCAN_USB_DRIVER_NAME, usb_id_product);
-               return -ENODEV;
-       }
+       peak_usb_adapter = (const struct peak_usb_adapter *)id->driver_info;
 
        /* got corresponding adapter: check if it handles current interface */
        if (peak_usb_adapter->intf_probe) {
index e15b4c7..b00a481 100644 (file)
@@ -31,7 +31,7 @@
 /* usb adapters maximum channels per usb interface */
 #define PCAN_USB_MAX_CHANNEL           2
 
-/* maximum length of the usb commands sent to/received from  the devices */
+/* maximum length of the usb commands sent to/received from the devices */
 #define PCAN_USB_MAX_CMD_LEN           32
 
 struct peak_usb_device;
@@ -73,7 +73,6 @@ struct peak_usb_adapter {
        u8 ep_msg_in;
        u8 ep_msg_out[PCAN_USB_MAX_CHANNEL];
        u8 ts_used_bits;
-       u32 ts_period;
        u8 us_per_ts_shift;
        u32 us_per_ts_scale;
 
@@ -114,8 +113,6 @@ struct peak_usb_device {
        unsigned int ctrl_idx;
        u32 state;
 
-       struct sk_buff *echo_skb[PCAN_USB_MAX_TX_URBS];
-
        struct usb_device *udev;
        struct net_device *netdev;
 
@@ -132,8 +129,6 @@ struct peak_usb_device {
        u8 ep_msg_in;
        u8 ep_msg_out;
 
-       u16 bus_load;
-
        struct peak_usb_device *prev_siblings;
        struct peak_usb_device *next_siblings;
 };
index 6f62b6f..b11eaba 100644 (file)
@@ -1081,7 +1081,6 @@ const struct peak_usb_adapter pcan_usb_fd = {
 
        /* timestamps usage */
        .ts_used_bits = 32,
-       .ts_period = 1000000, /* calibration period in ts. */
        .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
        .us_per_ts_shift = 0,
 
@@ -1156,7 +1155,6 @@ const struct peak_usb_adapter pcan_usb_chip = {
 
        /* timestamps usage */
        .ts_used_bits = 32,
-       .ts_period = 1000000, /* calibration period in ts. */
        .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
        .us_per_ts_shift = 0,
 
@@ -1231,7 +1229,6 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
 
        /* timestamps usage */
        .ts_used_bits = 32,
-       .ts_period = 1000000, /* calibration period in ts. */
        .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
        .us_per_ts_shift = 0,
 
@@ -1306,7 +1303,6 @@ const struct peak_usb_adapter pcan_usb_x6 = {
 
        /* timestamps usage */
        .ts_used_bits = 32,
-       .ts_period = 1000000, /* calibration period in ts. */
        .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
        .us_per_ts_shift = 0,
 
index 2d1b645..858ab22 100644 (file)
@@ -290,7 +290,7 @@ static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev,
                                           pr->data_type);
 
                        /* check if channel in response corresponds too */
-                       else if ((req_channel != 0xff) && \
+                       else if ((req_channel != 0xff) &&
                                (pr->bus_act.channel != req_channel))
                                netdev_err(dev->netdev,
                                        "got rsp %xh but on chan%u: ignored\n",
@@ -439,8 +439,7 @@ static int pcan_usb_pro_get_device_id(struct peak_usb_device *dev,
                return err;
 
        pdn = (struct pcan_usb_pro_devid *)pc;
-       if (device_id)
-               *device_id = le32_to_cpu(pdn->serial_num);
+       *device_id = le32_to_cpu(pdn->serial_num);
 
        return err;
 }
@@ -1058,7 +1057,6 @@ const struct peak_usb_adapter pcan_usb_pro = {
 
        /* timestamps usage */
        .ts_used_bits = 32,
-       .ts_period = 1000000, /* calibration period in ts. */
        .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
        .us_per_ts_shift = 0,
 
index 6f45043..5d4cf14 100644 (file)
 /* PCAN_USBPRO_INFO_BL vendor request record type */
 struct __packed pcan_usb_pro_blinfo {
        __le32 ctrl_type;
-       u8  version[4];
-       u8  day;
-       u8  month;
-       u8  year;
-       u8  dummy;
+       u8 version[4];
+       u8 day;
+       u8 month;
+       u8 year;
+       u8 dummy;
        __le32 serial_num_hi;
        __le32 serial_num_lo;
        __le32 hw_type;
@@ -48,11 +48,11 @@ struct __packed pcan_usb_pro_blinfo {
 /* PCAN_USBPRO_INFO_FW vendor request record type */
 struct __packed pcan_usb_pro_fwinfo {
        __le32 ctrl_type;
-       u8  version[4];
-       u8  day;
-       u8  month;
-       u8  year;
-       u8  dummy;
+       u8 version[4];
+       u8 day;
+       u8 month;
+       u8 year;
+       u8 dummy;
        __le32 fw_type;
 };
 
@@ -78,39 +78,39 @@ struct __packed pcan_usb_pro_fwinfo {
 
 /* record structures */
 struct __packed pcan_usb_pro_btr {
-       u8  data_type;
-       u8  channel;
+       u8 data_type;
+       u8 channel;
        __le16 dummy;
        __le32 CCBT;
 };
 
 struct __packed pcan_usb_pro_busact {
-       u8  data_type;
-       u8  channel;
+       u8 data_type;
+       u8 channel;
        __le16 onoff;
 };
 
 struct __packed pcan_usb_pro_silent {
-       u8  data_type;
-       u8  channel;
+       u8 data_type;
+       u8 channel;
        __le16 onoff;
 };
 
 struct __packed pcan_usb_pro_filter {
-       u8  data_type;
-       u8  dummy;
+       u8 data_type;
+       u8 dummy;
        __le16 filter_mode;
 };
 
 struct __packed pcan_usb_pro_setts {
-       u8  data_type;
-       u8  dummy;
+       u8 data_type;
+       u8 dummy;
        __le16 mode;
 };
 
 struct __packed pcan_usb_pro_devid {
-       u8  data_type;
-       u8  channel;
+       u8 data_type;
+       u8 channel;
        __le16 dummy;
        __le32 serial_num;
 };
@@ -122,21 +122,21 @@ struct __packed pcan_usb_pro_devid {
 #define PCAN_USBPRO_LED_OFF            0x04
 
 struct __packed pcan_usb_pro_setled {
-       u8  data_type;
-       u8  channel;
+       u8 data_type;
+       u8 channel;
        __le16 mode;
        __le32 timeout;
 };
 
 struct __packed pcan_usb_pro_rxmsg {
-       u8  data_type;
-       u8  client;
-       u8  flags;
-       u8  len;
+       u8 data_type;
+       u8 client;
+       u8 flags;
+       u8 len;
        __le32 ts32;
        __le32 id;
 
-       u8  data[8];
+       u8 data[8];
 };
 
 #define PCAN_USBPRO_STATUS_ERROR       0x0001
@@ -145,26 +145,26 @@ struct __packed pcan_usb_pro_rxmsg {
 #define PCAN_USBPRO_STATUS_QOVERRUN    0x0008
 
 struct __packed pcan_usb_pro_rxstatus {
-       u8  data_type;
-       u8  channel;
+       u8 data_type;
+       u8 channel;
        __le16 status;
        __le32 ts32;
        __le32 err_frm;
 };
 
 struct __packed pcan_usb_pro_rxts {
-       u8  data_type;
-       u8  dummy[3];
+       u8 data_type;
+       u8 dummy[3];
        __le32 ts64[2];
 };
 
 struct __packed pcan_usb_pro_txmsg {
-       u8  data_type;
-       u8  client;
-       u8  flags;
-       u8  len;
+       u8 data_type;
+       u8 client;
+       u8 flags;
+       u8 len;
        __le32 id;
-       u8  data[8];
+       u8 data[8];
 };
 
 union pcan_usb_pro_rec {
index 2bd1bab..96f7c9e 100644 (file)
@@ -2570,6 +2570,17 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
                        mcr |= PMCR_RX_FC_EN;
        }
 
+       if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, 0) >= 0) {
+               switch (speed) {
+               case SPEED_1000:
+                       mcr |= PMCR_FORCE_EEE1G;
+                       break;
+               case SPEED_100:
+                       mcr |= PMCR_FORCE_EEE100;
+                       break;
+               }
+       }
+
        mt7530_set(priv, MT7530_PMCR_P(port), mcr);
 }
 
@@ -2800,6 +2811,36 @@ mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
        return priv->info->phy_write(ds, port, regnum, val);
 }
 
+static int mt753x_get_mac_eee(struct dsa_switch *ds, int port,
+                             struct ethtool_eee *e)
+{
+       struct mt7530_priv *priv = ds->priv;
+       u32 eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port));
+
+       e->tx_lpi_enabled = !(eeecr & LPI_MODE_EN);
+       e->tx_lpi_timer = GET_LPI_THRESH(eeecr);
+
+       return 0;
+}
+
+static int mt753x_set_mac_eee(struct dsa_switch *ds, int port,
+                             struct ethtool_eee *e)
+{
+       struct mt7530_priv *priv = ds->priv;
+       u32 set, mask = LPI_THRESH_MASK | LPI_MODE_EN;
+
+       if (e->tx_lpi_timer > 0xFFF)
+               return -EINVAL;
+
+       set = SET_LPI_THRESH(e->tx_lpi_timer);
+       if (!e->tx_lpi_enabled)
+               /* Force LPI Mode without a delay */
+               set |= LPI_MODE_EN;
+       mt7530_rmw(priv, MT7530_PMEEECR_P(port), mask, set);
+
+       return 0;
+}
+
 static const struct dsa_switch_ops mt7530_switch_ops = {
        .get_tag_protocol       = mtk_get_tag_protocol,
        .setup                  = mt753x_setup,
@@ -2835,6 +2876,8 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
        .phylink_mac_an_restart = mt753x_phylink_mac_an_restart,
        .phylink_mac_link_down  = mt753x_phylink_mac_link_down,
        .phylink_mac_link_up    = mt753x_phylink_mac_link_up,
+       .get_mac_eee            = mt753x_get_mac_eee,
+       .set_mac_eee            = mt753x_set_mac_eee,
 };
 
 static const struct mt753x_info mt753x_table[] = {
index ec36ea5..0204da4 100644 (file)
@@ -257,6 +257,8 @@ enum mt7530_vlan_port_attr {
 #define  PMCR_RX_EN                    BIT(13)
 #define  PMCR_BACKOFF_EN               BIT(9)
 #define  PMCR_BACKPR_EN                        BIT(8)
+#define  PMCR_FORCE_EEE1G              BIT(7)
+#define  PMCR_FORCE_EEE100             BIT(6)
 #define  PMCR_TX_FC_EN                 BIT(5)
 #define  PMCR_RX_FC_EN                 BIT(4)
 #define  PMCR_FORCE_SPEED_1000         BIT(3)
@@ -281,7 +283,8 @@ enum mt7530_vlan_port_attr {
 #define  PMCR_LINK_SETTINGS_MASK       (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
                                         PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
                                         PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
-                                        PMCR_FORCE_FDX | PMCR_FORCE_LNK)
+                                        PMCR_FORCE_FDX | PMCR_FORCE_LNK | \
+                                        PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100)
 #define  PMCR_CPU_PORT_SETTING(id)     (PMCR_FORCE_MODE_ID((id)) | \
                                         PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
                                         PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
@@ -290,6 +293,15 @@ enum mt7530_vlan_port_attr {
                                         PMCR_FORCE_SPEED_1000 | \
                                         PMCR_FORCE_FDX | PMCR_FORCE_LNK)
 
+#define MT7530_PMEEECR_P(x)            (0x3004 + (x) * 0x100)
+#define  WAKEUP_TIME_1000(x)           (((x) & 0xFF) << 24)
+#define  WAKEUP_TIME_100(x)            (((x) & 0xFF) << 16)
+#define  LPI_THRESH_MASK               GENMASK(15, 4)
+#define  LPI_THRESH_SHT                        4
+#define  SET_LPI_THRESH(x)             (((x) << LPI_THRESH_SHT) & LPI_THRESH_MASK)
+#define  GET_LPI_THRESH(x)             (((x) & LPI_THRESH_MASK) >> LPI_THRESH_SHT)
+#define  LPI_MODE_EN                   BIT(0)
+
 #define MT7530_PMSR_P(x)               (0x3008 + (x) * 0x100)
 #define  PMSR_EEE1G                    BIT(7)
 #define  PMSR_EEE100M                  BIT(6)
index 9c5891b..d77fafb 100644 (file)
@@ -1449,10 +1449,10 @@ static int greth_of_probe(struct platform_device *ofdev)
                        break;
        }
        if (i == 6) {
-               const u8 *addr;
+               u8 addr[ETH_ALEN];
 
-               addr = of_get_mac_address(ofdev->dev.of_node);
-               if (!IS_ERR(addr)) {
+               err = of_get_mac_address(ofdev->dev.of_node, addr);
+               if (!err) {
                        for (i = 0; i < 6; i++)
                                macaddr[i] = (unsigned int) addr[i];
                } else {
index 5ed80d9..f99ae31 100644 (file)
@@ -790,7 +790,6 @@ static int emac_probe(struct platform_device *pdev)
        struct emac_board_info *db;
        struct net_device *ndev;
        int ret = 0;
-       const char *mac_addr;
 
        ndev = alloc_etherdev(sizeof(struct emac_board_info));
        if (!ndev) {
@@ -853,12 +852,9 @@ static int emac_probe(struct platform_device *pdev)
        }
 
        /* Read MAC-address from DT */
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(ndev->dev_addr, mac_addr);
-
-       /* Check if the MAC address is valid, if not get a random one */
-       if (!is_valid_ether_addr(ndev->dev_addr)) {
+       ret = of_get_mac_address(np, ndev->dev_addr);
+       if (ret) {
+               /* if the MAC address is invalid get a random one */
                eth_hw_addr_random(ndev);
                dev_warn(&pdev->dev, "using random MAC address %pM\n",
                         ndev->dev_addr);
index 907125a..1c00d71 100644 (file)
@@ -1351,7 +1351,6 @@ static int altera_tse_probe(struct platform_device *pdev)
        struct resource *control_port;
        struct resource *dma_res;
        struct altera_tse_private *priv;
-       const unsigned char *macaddr;
        void __iomem *descmap;
        const struct of_device_id *of_id = NULL;
 
@@ -1525,10 +1524,8 @@ static int altera_tse_probe(struct platform_device *pdev)
        priv->rx_dma_buf_sz = ALTERA_RXDMABUFFER_SIZE;
 
        /* get default MAC address from device tree */
-       macaddr = of_get_mac_address(pdev->dev.of_node);
-       if (!IS_ERR(macaddr))
-               ether_addr_copy(ndev->dev_addr, macaddr);
-       else
+       ret = of_get_mac_address(pdev->dev.of_node, ndev->dev_addr);
+       if (ret)
                eth_hw_addr_random(ndev);
 
        /* get phy addr and create mdio */
index b56a9e2..67b8113 100644 (file)
@@ -857,7 +857,6 @@ int arc_emac_probe(struct net_device *ndev, int interface)
        struct device_node *phy_node;
        struct phy_device *phydev = NULL;
        struct arc_emac_priv *priv;
-       const char *mac_addr;
        unsigned int id, clock_frequency, irq;
        int err;
 
@@ -942,11 +941,8 @@ int arc_emac_probe(struct net_device *ndev, int interface)
        }
 
        /* Get MAC address from device tree */
-       mac_addr = of_get_mac_address(dev->of_node);
-
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(ndev->dev_addr, mac_addr);
-       else
+       err = of_get_mac_address(dev->of_node, ndev->dev_addr);
+       if (err)
                eth_hw_addr_random(ndev);
 
        arc_emac_set_address_internal(ndev);
index 7352f98..3a23b92 100644 (file)
@@ -1856,7 +1856,6 @@ static int ag71xx_probe(struct platform_device *pdev)
        const struct ag71xx_dcfg *dcfg;
        struct net_device *ndev;
        struct resource *res;
-       const void *mac_addr;
        int tx_size, err, i;
        struct ag71xx *ag;
 
@@ -1957,10 +1956,8 @@ static int ag71xx_probe(struct platform_device *pdev)
        ag->stop_desc->ctrl = 0;
        ag->stop_desc->next = (u32)ag->stop_desc_dma;
 
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr))
-               memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
-       if (IS_ERR(mac_addr) || !is_valid_ether_addr(ndev->dev_addr)) {
+       err = of_get_mac_address(np, ndev->dev_addr);
+       if (err) {
                netif_err(ag, probe, ndev, "invalid MAC address, using random address\n");
                eth_random_addr(ndev->dev_addr);
        }
index b7afac5..60d9085 100644 (file)
@@ -686,7 +686,6 @@ static int bcm4908_enet_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct net_device *netdev;
        struct bcm4908_enet *enet;
-       const u8 *mac;
        int err;
 
        netdev = devm_alloc_etherdev(dev, sizeof(*enet));
@@ -716,10 +715,8 @@ static int bcm4908_enet_probe(struct platform_device *pdev)
                return err;
 
        SET_NETDEV_DEV(netdev, &pdev->dev);
-       mac = of_get_mac_address(dev->of_node);
-       if (!IS_ERR(mac))
-               ether_addr_copy(netdev->dev_addr, mac);
-       else
+       err = of_get_mac_address(dev->of_node, netdev->dev_addr);
+       if (err)
                eth_hw_addr_random(netdev);
        netdev->netdev_ops = &bcm4908_enet_netdev_ops;
        netdev->min_mtu = ETH_ZLEN;
index 777bbf6..d9f0f0d 100644 (file)
@@ -2457,7 +2457,6 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        struct bcm_sysport_priv *priv;
        struct device_node *dn;
        struct net_device *dev;
-       const void *macaddr;
        u32 txq, rxq;
        int ret;
 
@@ -2552,12 +2551,10 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        }
 
        /* Initialize netdevice members */
-       macaddr = of_get_mac_address(dn);
-       if (IS_ERR(macaddr)) {
+       ret = of_get_mac_address(dn, dev->dev_addr);
+       if (ret) {
                dev_warn(&pdev->dev, "using random Ethernet MAC\n");
                eth_hw_addr_random(dev);
-       } else {
-               ether_addr_copy(dev->dev_addr, macaddr);
        }
 
        SET_NETDEV_DEV(dev, &pdev->dev);
index a5fd161..85fa0ab 100644 (file)
@@ -115,7 +115,7 @@ static int bgmac_probe(struct bcma_device *core)
        struct ssb_sprom *sprom = &core->bus->sprom;
        struct mii_bus *mii_bus;
        struct bgmac *bgmac;
-       const u8 *mac = NULL;
+       const u8 *mac;
        int err;
 
        bgmac = bgmac_alloc(&core->dev);
@@ -128,11 +128,10 @@ static int bgmac_probe(struct bcma_device *core)
 
        bcma_set_drvdata(core, bgmac);
 
-       if (bgmac->dev->of_node)
-               mac = of_get_mac_address(bgmac->dev->of_node);
+       err = of_get_mac_address(bgmac->dev->of_node, bgmac->net_dev->dev_addr);
 
        /* If no MAC address assigned via device tree, check SPROM */
-       if (IS_ERR_OR_NULL(mac)) {
+       if (err) {
                switch (core->core_unit) {
                case 0:
                        mac = sprom->et0mac;
@@ -149,10 +148,9 @@ static int bgmac_probe(struct bcma_device *core)
                        err = -ENOTSUPP;
                        goto err;
                }
+               ether_addr_copy(bgmac->net_dev->dev_addr, mac);
        }
 
-       ether_addr_copy(bgmac->net_dev->dev_addr, mac);
-
        /* On BCM4706 we need common core to access PHY */
        if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
            !core->bus->drv_gmac_cmn.core) {
index f37f1c5..9834b77 100644 (file)
@@ -173,7 +173,7 @@ static int bgmac_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct bgmac *bgmac;
        struct resource *regs;
-       const u8 *mac_addr;
+       int ret;
 
        bgmac = bgmac_alloc(&pdev->dev);
        if (!bgmac)
@@ -192,11 +192,10 @@ static int bgmac_probe(struct platform_device *pdev)
        bgmac->dev = &pdev->dev;
        bgmac->dma_dev = &pdev->dev;
 
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(bgmac->net_dev->dev_addr, mac_addr);
-       else
-               dev_warn(&pdev->dev, "MAC address not present in device tree\n");
+       ret = of_get_mac_address(np, bgmac->net_dev->dev_addr);
+       if (ret)
+               dev_warn(&pdev->dev,
+                        "MAC address not present in device tree\n");
 
        bgmac->irq = platform_get_irq(pdev, 0);
        if (bgmac->irq < 0)
index ffd56a2..d6bde17 100644 (file)
@@ -4649,7 +4649,6 @@ static int macb_probe(struct platform_device *pdev)
        struct net_device *dev;
        struct resource *regs;
        void __iomem *mem;
-       const char *mac;
        struct macb *bp;
        int err, val;
 
@@ -4764,15 +4763,11 @@ static int macb_probe(struct platform_device *pdev)
        if (bp->caps & MACB_CAPS_NEEDS_RSTONUBR)
                bp->rx_intr_mask |= MACB_BIT(RXUBR);
 
-       mac = of_get_mac_address(np);
-       if (PTR_ERR(mac) == -EPROBE_DEFER) {
-               err = -EPROBE_DEFER;
+       err = of_get_mac_address(np, bp->dev->dev_addr);
+       if (err == -EPROBE_DEFER)
                goto err_out_free_netdev;
-       } else if (!IS_ERR_OR_NULL(mac)) {
-               ether_addr_copy(bp->dev->dev_addr, mac);
-       } else {
+       else if (err)
                macb_get_hwaddr(bp);
-       }
 
        err = of_get_phy_mode(np, &interface);
        if (err)
index ecffebd..48ff6fb 100644 (file)
@@ -1385,7 +1385,6 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
        struct net_device *netdev;
        struct octeon_mgmt *p;
        const __be32 *data;
-       const u8 *mac;
        struct resource *res_mix;
        struct resource *res_agl;
        struct resource *res_agl_prt_ctl;
@@ -1502,11 +1501,8 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
        netdev->min_mtu = 64 - OCTEON_MGMT_RX_HEADROOM;
        netdev->max_mtu = 16383 - OCTEON_MGMT_RX_HEADROOM - VLAN_HLEN;
 
-       mac = of_get_mac_address(pdev->dev.of_node);
-
-       if (!IS_ERR(mac))
-               ether_addr_copy(netdev->dev_addr, mac);
-       else
+       result = of_get_mac_address(pdev->dev.of_node, netdev->dev_addr);
+       if (result)
                eth_hw_addr_random(netdev);
 
        p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
index 8ff28ed..0c783aa 100644 (file)
@@ -1474,7 +1474,6 @@ static int bgx_init_of_phy(struct bgx *bgx)
        device_for_each_child_node(&bgx->pdev->dev, fwn) {
                struct phy_device *pd;
                struct device_node *phy_np;
-               const char *mac;
 
                /* Should always be an OF node.  But if it is not, we
                 * cannot handle it, so exit the loop.
@@ -1483,9 +1482,7 @@ static int bgx_init_of_phy(struct bgx *bgx)
                if (!node)
                        break;
 
-               mac = of_get_mac_address(node);
-               if (!IS_ERR(mac))
-                       ether_addr_copy(bgx->lmac[lmac].mac, mac);
+               of_get_mac_address(node, bgx->lmac[lmac].mac);
 
                SET_NETDEV_DEV(&bgx->lmac[lmac].netdev, &bgx->pdev->dev);
                bgx->lmac[lmac].lmacid = lmac;
index 252adfa..2374c51 100644 (file)
@@ -1385,7 +1385,7 @@ static struct dm9000_plat_data *dm9000_parse_dt(struct device *dev)
 {
        struct dm9000_plat_data *pdata;
        struct device_node *np = dev->of_node;
-       const void *mac_addr;
+       int ret;
 
        if (!IS_ENABLED(CONFIG_OF) || !np)
                return ERR_PTR(-ENXIO);
@@ -1399,11 +1399,9 @@ static struct dm9000_plat_data *dm9000_parse_dt(struct device *dev)
        if (of_find_property(np, "davicom,no-eeprom", NULL))
                pdata->flags |= DM9000_PLATF_NO_EEPROM;
 
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(pdata->dev_addr, mac_addr);
-       else if (PTR_ERR(mac_addr) == -EPROBE_DEFER)
-               return ERR_CAST(mac_addr);
+       ret = of_get_mac_address(np, pdata->dev_addr);
+       if (ret == -EPROBE_DEFER)
+               return ERR_PTR(ret);
 
        return pdata;
 }
index 3d9b0b1..e1b43b0 100644 (file)
@@ -1151,11 +1151,7 @@ static int ethoc_probe(struct platform_device *pdev)
                ether_addr_copy(netdev->dev_addr, pdata->hwaddr);
                priv->phy_id = pdata->phy_id;
        } else {
-               const void *mac;
-
-               mac = of_get_mac_address(pdev->dev.of_node);
-               if (!IS_ERR(mac))
-                       ether_addr_copy(netdev->dev_addr, mac);
+               of_get_mac_address(pdev->dev.of_node, netdev->dev_addr);
                priv->phy_id = -1;
        }
 
index 815fb62..e3954d8 100644 (file)
@@ -575,7 +575,6 @@ static s32 nps_enet_probe(struct platform_device *pdev)
        struct net_device *ndev;
        struct nps_enet_priv *priv;
        s32 err = 0;
-       const char *mac_addr;
 
        if (!dev->of_node)
                return -ENODEV;
@@ -602,10 +601,8 @@ static s32 nps_enet_probe(struct platform_device *pdev)
        dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs_base);
 
        /* set kernel MAC address to dev */
-       mac_addr = of_get_mac_address(dev->of_node);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(ndev->dev_addr, mac_addr);
-       else
+       err = of_get_mac_address(dev->of_node, ndev->dev_addr);
+       if (err)
                eth_hw_addr_random(ndev);
 
        /* Get IRQ number */
index 644ef9a..c2ef740 100644 (file)
@@ -11,7 +11,7 @@ fsl-dpaa2-eth-objs    := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o dpa
 fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_DCB} += dpaa2-eth-dcb.o
 fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o
 fsl-dpaa2-ptp-objs     := dpaa2-ptp.o dprtc.o
-fsl-dpaa2-switch-objs  := dpaa2-switch.o dpaa2-switch-ethtool.o dpsw.o
+fsl-dpaa2-switch-objs  := dpaa2-switch.o dpaa2-switch-ethtool.o dpsw.o dpaa2-switch-flower.o
 
 # Needed by the tracing framework
 CFLAGS_dpaa2-eth.o := -I$(src)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c
new file mode 100644 (file)
index 0000000..f9451ec
--- /dev/null
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DPAA2 Ethernet Switch flower support
+ *
+ * Copyright 2021 NXP
+ *
+ */
+
+#include "dpaa2-switch.h"
+
+static int dpaa2_switch_flower_parse_key(struct flow_cls_offload *cls,
+                                        struct dpsw_acl_key *acl_key)
+{
+       struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
+       struct flow_dissector *dissector = rule->match.dissector;
+       struct netlink_ext_ack *extack = cls->common.extack;
+       struct dpsw_acl_fields *acl_h, *acl_m;
+
+       if (dissector->used_keys &
+           ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
+             BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+             BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+             BIT(FLOW_DISSECTOR_KEY_VLAN) |
+             BIT(FLOW_DISSECTOR_KEY_PORTS) |
+             BIT(FLOW_DISSECTOR_KEY_IP) |
+             BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+             BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS))) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Unsupported keys used");
+               return -EOPNOTSUPP;
+       }
+
+       acl_h = &acl_key->match;
+       acl_m = &acl_key->mask;
+
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
+               struct flow_match_basic match;
+
+               flow_rule_match_basic(rule, &match);
+               acl_h->l3_protocol = match.key->ip_proto;
+               acl_h->l2_ether_type = be16_to_cpu(match.key->n_proto);
+               acl_m->l3_protocol = match.mask->ip_proto;
+               acl_m->l2_ether_type = be16_to_cpu(match.mask->n_proto);
+       }
+
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+               struct flow_match_eth_addrs match;
+
+               flow_rule_match_eth_addrs(rule, &match);
+               ether_addr_copy(acl_h->l2_dest_mac, &match.key->dst[0]);
+               ether_addr_copy(acl_h->l2_source_mac, &match.key->src[0]);
+               ether_addr_copy(acl_m->l2_dest_mac, &match.mask->dst[0]);
+               ether_addr_copy(acl_m->l2_source_mac, &match.mask->src[0]);
+       }
+
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
+               struct flow_match_vlan match;
+
+               flow_rule_match_vlan(rule, &match);
+               acl_h->l2_vlan_id = match.key->vlan_id;
+               acl_h->l2_tpid = be16_to_cpu(match.key->vlan_tpid);
+               acl_h->l2_pcp_dei = match.key->vlan_priority << 1 |
+                                   match.key->vlan_dei;
+
+               acl_m->l2_vlan_id = match.mask->vlan_id;
+               acl_m->l2_tpid = be16_to_cpu(match.mask->vlan_tpid);
+               acl_m->l2_pcp_dei = match.mask->vlan_priority << 1 |
+                                   match.mask->vlan_dei;
+       }
+
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
+               struct flow_match_ipv4_addrs match;
+
+               flow_rule_match_ipv4_addrs(rule, &match);
+               acl_h->l3_source_ip = be32_to_cpu(match.key->src);
+               acl_h->l3_dest_ip = be32_to_cpu(match.key->dst);
+               acl_m->l3_source_ip = be32_to_cpu(match.mask->src);
+               acl_m->l3_dest_ip = be32_to_cpu(match.mask->dst);
+       }
+
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
+               struct flow_match_ports match;
+
+               flow_rule_match_ports(rule, &match);
+               acl_h->l4_source_port = be16_to_cpu(match.key->src);
+               acl_h->l4_dest_port = be16_to_cpu(match.key->dst);
+               acl_m->l4_source_port = be16_to_cpu(match.mask->src);
+               acl_m->l4_dest_port = be16_to_cpu(match.mask->dst);
+       }
+
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
+               struct flow_match_ip match;
+
+               flow_rule_match_ip(rule, &match);
+               if (match.mask->ttl != 0) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Matching on TTL not supported");
+                       return -EOPNOTSUPP;
+               }
+
+               if ((match.mask->tos & 0x3) != 0) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Matching on ECN not supported, only DSCP");
+                       return -EOPNOTSUPP;
+               }
+
+               acl_h->l3_dscp = match.key->tos >> 2;
+               acl_m->l3_dscp = match.mask->tos >> 2;
+       }
+
+       return 0;
+}
+
+int dpaa2_switch_acl_entry_add(struct dpaa2_switch_acl_tbl *acl_tbl,
+                              struct dpaa2_switch_acl_entry *entry)
+{
+       struct dpsw_acl_entry_cfg *acl_entry_cfg = &entry->cfg;
+       struct ethsw_core *ethsw = acl_tbl->ethsw;
+       struct dpsw_acl_key *acl_key = &entry->key;
+       struct device *dev = ethsw->dev;
+       u8 *cmd_buff;
+       int err;
+
+       cmd_buff = kzalloc(DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE, GFP_KERNEL);
+       if (!cmd_buff)
+               return -ENOMEM;
+
+       dpsw_acl_prepare_entry_cfg(acl_key, cmd_buff);
+
+       acl_entry_cfg->key_iova = dma_map_single(dev, cmd_buff,
+                                                DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE,
+                                                DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(dev, acl_entry_cfg->key_iova))) {
+               dev_err(dev, "DMA mapping failed\n");
+               return -EFAULT;
+       }
+
+       err = dpsw_acl_add_entry(ethsw->mc_io, 0, ethsw->dpsw_handle,
+                                acl_tbl->id, acl_entry_cfg);
+
+       dma_unmap_single(dev, acl_entry_cfg->key_iova, sizeof(cmd_buff),
+                        DMA_TO_DEVICE);
+       if (err) {
+               dev_err(dev, "dpsw_acl_add_entry() failed %d\n", err);
+               return err;
+       }
+
+       kfree(cmd_buff);
+
+       return 0;
+}
+
+static int dpaa2_switch_acl_entry_remove(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                        struct dpaa2_switch_acl_entry *entry)
+{
+       struct dpsw_acl_entry_cfg *acl_entry_cfg = &entry->cfg;
+       struct dpsw_acl_key *acl_key = &entry->key;
+       struct ethsw_core *ethsw = acl_tbl->ethsw;
+       struct device *dev = ethsw->dev;
+       u8 *cmd_buff;
+       int err;
+
+       cmd_buff = kzalloc(DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE, GFP_KERNEL);
+       if (!cmd_buff)
+               return -ENOMEM;
+
+       dpsw_acl_prepare_entry_cfg(acl_key, cmd_buff);
+
+       acl_entry_cfg->key_iova = dma_map_single(dev, cmd_buff,
+                                                DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE,
+                                                DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(dev, acl_entry_cfg->key_iova))) {
+               dev_err(dev, "DMA mapping failed\n");
+               return -EFAULT;
+       }
+
+       err = dpsw_acl_remove_entry(ethsw->mc_io, 0, ethsw->dpsw_handle,
+                                   acl_tbl->id, acl_entry_cfg);
+
+       dma_unmap_single(dev, acl_entry_cfg->key_iova, sizeof(cmd_buff),
+                        DMA_TO_DEVICE);
+       if (err) {
+               dev_err(dev, "dpsw_acl_remove_entry() failed %d\n", err);
+               return err;
+       }
+
+       kfree(cmd_buff);
+
+       return 0;
+}
+
+static int
+dpaa2_switch_acl_entry_add_to_list(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                  struct dpaa2_switch_acl_entry *entry)
+{
+       struct dpaa2_switch_acl_entry *tmp;
+       struct list_head *pos, *n;
+       int index = 0;
+
+       if (list_empty(&acl_tbl->entries)) {
+               list_add(&entry->list, &acl_tbl->entries);
+               return index;
+       }
+
+       list_for_each_safe(pos, n, &acl_tbl->entries) {
+               tmp = list_entry(pos, struct dpaa2_switch_acl_entry, list);
+               if (entry->prio < tmp->prio)
+                       break;
+               index++;
+       }
+       list_add(&entry->list, pos->prev);
+       return index;
+}
+
+static struct dpaa2_switch_acl_entry*
+dpaa2_switch_acl_entry_get_by_index(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                   int index)
+{
+       struct dpaa2_switch_acl_entry *tmp;
+       int i = 0;
+
+       list_for_each_entry(tmp, &acl_tbl->entries, list) {
+               if (i == index)
+                       return tmp;
+               ++i;
+       }
+
+       return NULL;
+}
+
+static int
+dpaa2_switch_acl_entry_set_precedence(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                     struct dpaa2_switch_acl_entry *entry,
+                                     int precedence)
+{
+       int err;
+
+       err = dpaa2_switch_acl_entry_remove(acl_tbl, entry);
+       if (err)
+               return err;
+
+       entry->cfg.precedence = precedence;
+       return dpaa2_switch_acl_entry_add(acl_tbl, entry);
+}
+
+static int dpaa2_switch_acl_tbl_add_entry(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                         struct dpaa2_switch_acl_entry *entry)
+{
+       struct dpaa2_switch_acl_entry *tmp;
+       int index, i, precedence, err;
+
+       /* Add the new ACL entry to the linked list and get its index */
+       index = dpaa2_switch_acl_entry_add_to_list(acl_tbl, entry);
+
+       /* Move up in priority the ACL entries to make space
+        * for the new filter.
+        */
+       precedence = DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES - acl_tbl->num_rules - 1;
+       for (i = 0; i < index; i++) {
+               tmp = dpaa2_switch_acl_entry_get_by_index(acl_tbl, i);
+
+               err = dpaa2_switch_acl_entry_set_precedence(acl_tbl, tmp,
+                                                           precedence);
+               if (err)
+                       return err;
+
+               precedence++;
+       }
+
+       /* Add the new entry to hardware */
+       entry->cfg.precedence = precedence;
+       err = dpaa2_switch_acl_entry_add(acl_tbl, entry);
+       acl_tbl->num_rules++;
+
+       return err;
+}
+
+static struct dpaa2_switch_acl_entry *
+dpaa2_switch_acl_tbl_find_entry_by_cookie(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                         unsigned long cookie)
+{
+       struct dpaa2_switch_acl_entry *tmp, *n;
+
+       list_for_each_entry_safe(tmp, n, &acl_tbl->entries, list) {
+               if (tmp->cookie == cookie)
+                       return tmp;
+       }
+       return NULL;
+}
+
+static int
+dpaa2_switch_acl_entry_get_index(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                struct dpaa2_switch_acl_entry *entry)
+{
+       struct dpaa2_switch_acl_entry *tmp, *n;
+       int index = 0;
+
+       list_for_each_entry_safe(tmp, n, &acl_tbl->entries, list) {
+               if (tmp->cookie == entry->cookie)
+                       return index;
+               index++;
+       }
+       return -ENOENT;
+}
+
+static int
+dpaa2_switch_acl_tbl_remove_entry(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                 struct dpaa2_switch_acl_entry *entry)
+{
+       struct dpaa2_switch_acl_entry *tmp;
+       int index, i, precedence, err;
+
+       index = dpaa2_switch_acl_entry_get_index(acl_tbl, entry);
+
+       /* Remove from hardware the ACL entry */
+       err = dpaa2_switch_acl_entry_remove(acl_tbl, entry);
+       if (err)
+               return err;
+
+       acl_tbl->num_rules--;
+
+       /* Remove it from the list also */
+       list_del(&entry->list);
+
+       /* Move down in priority the entries over the deleted one */
+       precedence = entry->cfg.precedence;
+       for (i = index - 1; i >= 0; i--) {
+               tmp = dpaa2_switch_acl_entry_get_by_index(acl_tbl, i);
+               err = dpaa2_switch_acl_entry_set_precedence(acl_tbl, tmp,
+                                                           precedence);
+               if (err)
+                       return err;
+
+               precedence--;
+       }
+
+       kfree(entry);
+
+       return 0;
+}
+
+static int dpaa2_switch_tc_parse_action(struct ethsw_core *ethsw,
+                                       struct flow_action_entry *cls_act,
+                                       struct dpsw_acl_result *dpsw_act,
+                                       struct netlink_ext_ack *extack)
+{
+       int err = 0;
+
+       switch (cls_act->id) {
+       case FLOW_ACTION_TRAP:
+               dpsw_act->action = DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF;
+               break;
+       case FLOW_ACTION_REDIRECT:
+               if (!dpaa2_switch_port_dev_check(cls_act->dev)) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Destination not a DPAA2 switch port");
+                       return -EOPNOTSUPP;
+               }
+
+               dpsw_act->if_id = dpaa2_switch_get_index(ethsw, cls_act->dev);
+               dpsw_act->action = DPSW_ACL_ACTION_REDIRECT;
+               break;
+       case FLOW_ACTION_DROP:
+               dpsw_act->action = DPSW_ACL_ACTION_DROP;
+               break;
+       default:
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Action not supported");
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+out:
+       return err;
+}
+
+int dpaa2_switch_cls_flower_replace(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                   struct flow_cls_offload *cls)
+{
+       struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
+       struct netlink_ext_ack *extack = cls->common.extack;
+       struct ethsw_core *ethsw = acl_tbl->ethsw;
+       struct dpaa2_switch_acl_entry *acl_entry;
+       struct flow_action_entry *act;
+       int err;
+
+       if (!flow_offload_has_one_action(&rule->action)) {
+               NL_SET_ERR_MSG(extack, "Only singular actions are supported");
+               return -EOPNOTSUPP;
+       }
+
+       if (dpaa2_switch_acl_tbl_is_full(acl_tbl)) {
+               NL_SET_ERR_MSG(extack, "Maximum filter capacity reached");
+               return -ENOMEM;
+       }
+
+       acl_entry = kzalloc(sizeof(*acl_entry), GFP_KERNEL);
+       if (!acl_entry)
+               return -ENOMEM;
+
+       err = dpaa2_switch_flower_parse_key(cls, &acl_entry->key);
+       if (err)
+               goto free_acl_entry;
+
+       act = &rule->action.entries[0];
+       err = dpaa2_switch_tc_parse_action(ethsw, act,
+                                          &acl_entry->cfg.result, extack);
+       if (err)
+               goto free_acl_entry;
+
+       acl_entry->prio = cls->common.prio;
+       acl_entry->cookie = cls->cookie;
+
+       err = dpaa2_switch_acl_tbl_add_entry(acl_tbl, acl_entry);
+       if (err)
+               goto free_acl_entry;
+
+       return 0;
+
+free_acl_entry:
+       kfree(acl_entry);
+
+       return err;
+}
+
+int dpaa2_switch_cls_flower_destroy(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                   struct flow_cls_offload *cls)
+{
+       struct dpaa2_switch_acl_entry *entry;
+
+       entry = dpaa2_switch_acl_tbl_find_entry_by_cookie(acl_tbl, cls->cookie);
+       if (!entry)
+               return 0;
+
+       return dpaa2_switch_acl_tbl_remove_entry(acl_tbl, entry);
+}
+
+int dpaa2_switch_cls_matchall_replace(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                     struct tc_cls_matchall_offload *cls)
+{
+       struct netlink_ext_ack *extack = cls->common.extack;
+       struct ethsw_core *ethsw = acl_tbl->ethsw;
+       struct dpaa2_switch_acl_entry *acl_entry;
+       struct flow_action_entry *act;
+       int err;
+
+       if (!flow_offload_has_one_action(&cls->rule->action)) {
+               NL_SET_ERR_MSG(extack, "Only singular actions are supported");
+               return -EOPNOTSUPP;
+       }
+
+       if (dpaa2_switch_acl_tbl_is_full(acl_tbl)) {
+               NL_SET_ERR_MSG(extack, "Maximum filter capacity reached");
+               return -ENOMEM;
+       }
+
+       acl_entry = kzalloc(sizeof(*acl_entry), GFP_KERNEL);
+       if (!acl_entry)
+               return -ENOMEM;
+
+       act = &cls->rule->action.entries[0];
+       err = dpaa2_switch_tc_parse_action(ethsw, act,
+                                          &acl_entry->cfg.result, extack);
+       if (err)
+               goto free_acl_entry;
+
+       acl_entry->prio = cls->common.prio;
+       acl_entry->cookie = cls->cookie;
+
+       err = dpaa2_switch_acl_tbl_add_entry(acl_tbl, acl_entry);
+       if (err)
+               goto free_acl_entry;
+
+       return 0;
+
+free_acl_entry:
+       kfree(acl_entry);
+
+       return err;
+}
+
+int dpaa2_switch_cls_matchall_destroy(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                     struct tc_cls_matchall_offload *cls)
+{
+       struct dpaa2_switch_acl_entry *entry;
+
+       entry = dpaa2_switch_acl_tbl_find_entry_by_cookie(acl_tbl, cls->cookie);
+       if (!entry)
+               return 0;
+
+       return  dpaa2_switch_acl_tbl_remove_entry(acl_tbl, entry);
+}
index 80efc81..5250d51 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kthread.h>
 #include <linux/workqueue.h>
 #include <linux/iommu.h>
+#include <net/pkt_cls.h>
 
 #include <linux/fsl/mc.h>
 
@@ -40,6 +41,17 @@ static struct dpaa2_switch_fdb *dpaa2_switch_fdb_get_unused(struct ethsw_core *e
        return NULL;
 }
 
+static struct dpaa2_switch_acl_tbl *
+dpaa2_switch_acl_tbl_get_unused(struct ethsw_core *ethsw)
+{
+       int i;
+
+       for (i = 0; i < ethsw->sw_attr.num_ifs; i++)
+               if (!ethsw->acls[i].in_use)
+                       return &ethsw->acls[i];
+       return NULL;
+}
+
 static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
                                     struct net_device *bridge_dev)
 {
@@ -1114,6 +1126,259 @@ err_exit:
        return NETDEV_TX_OK;
 }
 
+static int
+dpaa2_switch_setup_tc_cls_flower(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                struct flow_cls_offload *f)
+{
+       switch (f->command) {
+       case FLOW_CLS_REPLACE:
+               return dpaa2_switch_cls_flower_replace(acl_tbl, f);
+       case FLOW_CLS_DESTROY:
+               return dpaa2_switch_cls_flower_destroy(acl_tbl, f);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int
+dpaa2_switch_setup_tc_cls_matchall(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                  struct tc_cls_matchall_offload *f)
+{
+       switch (f->command) {
+       case TC_CLSMATCHALL_REPLACE:
+               return dpaa2_switch_cls_matchall_replace(acl_tbl, f);
+       case TC_CLSMATCHALL_DESTROY:
+               return dpaa2_switch_cls_matchall_destroy(acl_tbl, f);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int dpaa2_switch_port_setup_tc_block_cb_ig(enum tc_setup_type type,
+                                                 void *type_data,
+                                                 void *cb_priv)
+{
+       switch (type) {
+       case TC_SETUP_CLSFLOWER:
+               return dpaa2_switch_setup_tc_cls_flower(cb_priv, type_data);
+       case TC_SETUP_CLSMATCHALL:
+               return dpaa2_switch_setup_tc_cls_matchall(cb_priv, type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static LIST_HEAD(dpaa2_switch_block_cb_list);
+
+static int dpaa2_switch_port_acl_tbl_bind(struct ethsw_port_priv *port_priv,
+                                         struct dpaa2_switch_acl_tbl *acl_tbl)
+{
+       struct ethsw_core *ethsw = port_priv->ethsw_data;
+       struct net_device *netdev = port_priv->netdev;
+       struct dpsw_acl_if_cfg acl_if_cfg;
+       int err;
+
+       if (port_priv->acl_tbl)
+               return -EINVAL;
+
+       acl_if_cfg.if_id[0] = port_priv->idx;
+       acl_if_cfg.num_ifs = 1;
+       err = dpsw_acl_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle,
+                             acl_tbl->id, &acl_if_cfg);
+       if (err) {
+               netdev_err(netdev, "dpsw_acl_add_if err %d\n", err);
+               return err;
+       }
+
+       acl_tbl->ports |= BIT(port_priv->idx);
+       port_priv->acl_tbl = acl_tbl;
+
+       return 0;
+}
+
+static int
+dpaa2_switch_port_acl_tbl_unbind(struct ethsw_port_priv *port_priv,
+                                struct dpaa2_switch_acl_tbl *acl_tbl)
+{
+       struct ethsw_core *ethsw = port_priv->ethsw_data;
+       struct net_device *netdev = port_priv->netdev;
+       struct dpsw_acl_if_cfg acl_if_cfg;
+       int err;
+
+       if (port_priv->acl_tbl != acl_tbl)
+               return -EINVAL;
+
+       acl_if_cfg.if_id[0] = port_priv->idx;
+       acl_if_cfg.num_ifs = 1;
+       err = dpsw_acl_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle,
+                                acl_tbl->id, &acl_if_cfg);
+       if (err) {
+               netdev_err(netdev, "dpsw_acl_add_if err %d\n", err);
+               return err;
+       }
+
+       acl_tbl->ports &= ~BIT(port_priv->idx);
+       port_priv->acl_tbl = NULL;
+       return 0;
+}
+
+static int dpaa2_switch_port_block_bind(struct ethsw_port_priv *port_priv,
+                                       struct dpaa2_switch_acl_tbl *acl_tbl)
+{
+       struct dpaa2_switch_acl_tbl *old_acl_tbl = port_priv->acl_tbl;
+       int err;
+
+       /* If the port is already bound to this ACL table then do nothing. This
+        * can happen when this port is the first one to join a tc block
+        */
+       if (port_priv->acl_tbl == acl_tbl)
+               return 0;
+
+       err = dpaa2_switch_port_acl_tbl_unbind(port_priv, old_acl_tbl);
+       if (err)
+               return err;
+
+       /* Mark the previous ACL table as being unused if this was the last
+        * port that was using it.
+        */
+       if (old_acl_tbl->ports == 0)
+               old_acl_tbl->in_use = false;
+
+       return dpaa2_switch_port_acl_tbl_bind(port_priv, acl_tbl);
+}
+
+static int dpaa2_switch_port_block_unbind(struct ethsw_port_priv *port_priv,
+                                         struct dpaa2_switch_acl_tbl *acl_tbl)
+{
+       struct ethsw_core *ethsw = port_priv->ethsw_data;
+       struct dpaa2_switch_acl_tbl *new_acl_tbl;
+       int err;
+
+       /* We are the last port that leaves a block (an ACL table).
+        * We'll continue to use this table.
+        */
+       if (acl_tbl->ports == BIT(port_priv->idx))
+               return 0;
+
+       err = dpaa2_switch_port_acl_tbl_unbind(port_priv, acl_tbl);
+       if (err)
+               return err;
+
+       if (acl_tbl->ports == 0)
+               acl_tbl->in_use = false;
+
+       new_acl_tbl = dpaa2_switch_acl_tbl_get_unused(ethsw);
+       new_acl_tbl->in_use = true;
+       return dpaa2_switch_port_acl_tbl_bind(port_priv, new_acl_tbl);
+}
+
+static int dpaa2_switch_setup_tc_block_bind(struct net_device *netdev,
+                                           struct flow_block_offload *f)
+{
+       struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+       struct ethsw_core *ethsw = port_priv->ethsw_data;
+       struct dpaa2_switch_acl_tbl *acl_tbl;
+       struct flow_block_cb *block_cb;
+       bool register_block = false;
+       int err;
+
+       block_cb = flow_block_cb_lookup(f->block,
+                                       dpaa2_switch_port_setup_tc_block_cb_ig,
+                                       ethsw);
+
+       if (!block_cb) {
+               /* If the ACL table is not already known, then this port must
+                * be the first to join it. In this case, we can just continue
+                * to use our private table
+                */
+               acl_tbl = port_priv->acl_tbl;
+
+               block_cb = flow_block_cb_alloc(dpaa2_switch_port_setup_tc_block_cb_ig,
+                                              ethsw, acl_tbl, NULL);
+               if (IS_ERR(block_cb))
+                       return PTR_ERR(block_cb);
+
+               register_block = true;
+       } else {
+               acl_tbl = flow_block_cb_priv(block_cb);
+       }
+
+       flow_block_cb_incref(block_cb);
+       err = dpaa2_switch_port_block_bind(port_priv, acl_tbl);
+       if (err)
+               goto err_block_bind;
+
+       if (register_block) {
+               flow_block_cb_add(block_cb, f);
+               list_add_tail(&block_cb->driver_list,
+                             &dpaa2_switch_block_cb_list);
+       }
+
+       return 0;
+
+err_block_bind:
+       if (!flow_block_cb_decref(block_cb))
+               flow_block_cb_free(block_cb);
+       return err;
+}
+
+static void dpaa2_switch_setup_tc_block_unbind(struct net_device *netdev,
+                                              struct flow_block_offload *f)
+{
+       struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+       struct ethsw_core *ethsw = port_priv->ethsw_data;
+       struct dpaa2_switch_acl_tbl *acl_tbl;
+       struct flow_block_cb *block_cb;
+       int err;
+
+       block_cb = flow_block_cb_lookup(f->block,
+                                       dpaa2_switch_port_setup_tc_block_cb_ig,
+                                       ethsw);
+       if (!block_cb)
+               return;
+
+       acl_tbl = flow_block_cb_priv(block_cb);
+       err = dpaa2_switch_port_block_unbind(port_priv, acl_tbl);
+       if (!err && !flow_block_cb_decref(block_cb)) {
+               flow_block_cb_remove(block_cb, f);
+               list_del(&block_cb->driver_list);
+       }
+}
+
+static int dpaa2_switch_setup_tc_block(struct net_device *netdev,
+                                      struct flow_block_offload *f)
+{
+       if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+               return -EOPNOTSUPP;
+
+       f->driver_block_list = &dpaa2_switch_block_cb_list;
+
+       switch (f->command) {
+       case FLOW_BLOCK_BIND:
+               return dpaa2_switch_setup_tc_block_bind(netdev, f);
+       case FLOW_BLOCK_UNBIND:
+               dpaa2_switch_setup_tc_block_unbind(netdev, f);
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int dpaa2_switch_port_setup_tc(struct net_device *netdev,
+                                     enum tc_setup_type type,
+                                     void *type_data)
+{
+       switch (type) {
+       case TC_SETUP_BLOCK: {
+               return dpaa2_switch_setup_tc_block(netdev, type_data);
+       }
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static const struct net_device_ops dpaa2_switch_port_ops = {
        .ndo_open               = dpaa2_switch_port_open,
        .ndo_stop               = dpaa2_switch_port_stop,
@@ -1130,6 +1395,7 @@ static const struct net_device_ops dpaa2_switch_port_ops = {
        .ndo_start_xmit         = dpaa2_switch_port_tx,
        .ndo_get_port_parent_id = dpaa2_switch_port_parent_id,
        .ndo_get_phys_port_name = dpaa2_switch_port_get_phys_name,
+       .ndo_setup_tc           = dpaa2_switch_port_setup_tc,
 };
 
 bool dpaa2_switch_port_dev_check(const struct net_device *netdev)
@@ -2676,61 +2942,17 @@ err_close:
 static int dpaa2_switch_port_trap_mac_addr(struct ethsw_port_priv *port_priv,
                                           const char *mac)
 {
-       struct net_device *netdev = port_priv->netdev;
-       struct dpsw_acl_entry_cfg acl_entry_cfg;
-       struct dpsw_acl_fields *acl_h;
-       struct dpsw_acl_fields *acl_m;
-       struct dpsw_acl_key acl_key;
-       struct device *dev;
-       u8 *cmd_buff;
-       int err;
-
-       dev = port_priv->netdev->dev.parent;
-       acl_h = &acl_key.match;
-       acl_m = &acl_key.mask;
-
-       if (port_priv->acl_num_rules >= DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES) {
-               netdev_err(netdev, "ACL full\n");
-               return -ENOMEM;
-       }
-
-       memset(&acl_entry_cfg, 0, sizeof(acl_entry_cfg));
-       memset(&acl_key, 0, sizeof(acl_key));
+       struct dpaa2_switch_acl_entry acl_entry = {0};
 
        /* Match on the destination MAC address */
-       ether_addr_copy(acl_h->l2_dest_mac, mac);
-       eth_broadcast_addr(acl_m->l2_dest_mac);
+       ether_addr_copy(acl_entry.key.match.l2_dest_mac, mac);
+       eth_broadcast_addr(acl_entry.key.mask.l2_dest_mac);
 
-       cmd_buff = kzalloc(DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE, GFP_KERNEL);
-       if (!cmd_buff)
-               return -ENOMEM;
-       dpsw_acl_prepare_entry_cfg(&acl_key, cmd_buff);
-
-       memset(&acl_entry_cfg, 0, sizeof(acl_entry_cfg));
-       acl_entry_cfg.precedence = port_priv->acl_num_rules;
-       acl_entry_cfg.result.action = DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF;
-       acl_entry_cfg.key_iova = dma_map_single(dev, cmd_buff,
-                                               DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE,
-                                               DMA_TO_DEVICE);
-       if (unlikely(dma_mapping_error(dev, acl_entry_cfg.key_iova))) {
-               netdev_err(netdev, "DMA mapping failed\n");
-               return -EFAULT;
-       }
+       /* Trap to CPU */
+       acl_entry.cfg.precedence = 0;
+       acl_entry.cfg.result.action = DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF;
 
-       err = dpsw_acl_add_entry(port_priv->ethsw_data->mc_io, 0,
-                                port_priv->ethsw_data->dpsw_handle,
-                                port_priv->acl_tbl, &acl_entry_cfg);
-
-       dma_unmap_single(dev, acl_entry_cfg.key_iova, sizeof(cmd_buff),
-                        DMA_TO_DEVICE);
-       if (err) {
-               netdev_err(netdev, "dpsw_acl_add_entry() failed %d\n", err);
-               return err;
-       }
-
-       port_priv->acl_num_rules++;
-
-       return 0;
+       return dpaa2_switch_acl_entry_add(port_priv->acl_tbl, &acl_entry);
 }
 
 static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port)
@@ -2743,12 +2965,12 @@ static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port)
        };
        struct net_device *netdev = port_priv->netdev;
        struct ethsw_core *ethsw = port_priv->ethsw_data;
+       struct dpaa2_switch_acl_tbl *acl_tbl;
        struct dpsw_fdb_cfg fdb_cfg = {0};
-       struct dpsw_acl_if_cfg acl_if_cfg;
        struct dpsw_if_attr dpsw_if_attr;
        struct dpaa2_switch_fdb *fdb;
        struct dpsw_acl_cfg acl_cfg;
-       u16 fdb_id;
+       u16 fdb_id, acl_tbl_id;
        int err;
 
        /* Get the Tx queue for this specific port */
@@ -2792,21 +3014,22 @@ static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port)
        /* Create an ACL table to be used by this switch port */
        acl_cfg.max_entries = DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES;
        err = dpsw_acl_add(ethsw->mc_io, 0, ethsw->dpsw_handle,
-                          &port_priv->acl_tbl, &acl_cfg);
+                          &acl_tbl_id, &acl_cfg);
        if (err) {
                netdev_err(netdev, "dpsw_acl_add err %d\n", err);
                return err;
        }
 
-       acl_if_cfg.if_id[0] = port_priv->idx;
-       acl_if_cfg.num_ifs = 1;
-       err = dpsw_acl_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle,
-                             port_priv->acl_tbl, &acl_if_cfg);
-       if (err) {
-               netdev_err(netdev, "dpsw_acl_add_if err %d\n", err);
-               dpsw_acl_remove(ethsw->mc_io, 0, ethsw->dpsw_handle,
-                               port_priv->acl_tbl);
-       }
+       acl_tbl = dpaa2_switch_acl_tbl_get_unused(ethsw);
+       acl_tbl->ethsw = ethsw;
+       acl_tbl->id = acl_tbl_id;
+       acl_tbl->in_use = true;
+       acl_tbl->num_rules = 0;
+       INIT_LIST_HEAD(&acl_tbl->entries);
+
+       err = dpaa2_switch_port_acl_tbl_bind(port_priv, acl_tbl);
+       if (err)
+               return err;
 
        err = dpaa2_switch_port_trap_mac_addr(port_priv, stpa);
        if (err)
@@ -2858,6 +3081,7 @@ static int dpaa2_switch_remove(struct fsl_mc_device *sw_dev)
        }
 
        kfree(ethsw->fdbs);
+       kfree(ethsw->acls);
        kfree(ethsw->ports);
 
        dpaa2_switch_takedown(sw_dev);
@@ -2915,7 +3139,9 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
        /* The DPAA2 switch's ingress path depends on the VLAN table,
         * thus we are not able to disable VLAN filtering.
         */
-       port_netdev->features = NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER;
+       port_netdev->features = NETIF_F_HW_VLAN_CTAG_FILTER |
+                               NETIF_F_HW_VLAN_STAG_FILTER |
+                               NETIF_F_HW_TC;
 
        err = dpaa2_switch_port_init(port_priv, port_idx);
        if (err)
@@ -2983,6 +3209,13 @@ static int dpaa2_switch_probe(struct fsl_mc_device *sw_dev)
                goto err_free_ports;
        }
 
+       ethsw->acls = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->acls),
+                             GFP_KERNEL);
+       if (!ethsw->acls) {
+               err = -ENOMEM;
+               goto err_free_fdbs;
+       }
+
        for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
                err = dpaa2_switch_probe_port(ethsw, i);
                if (err)
@@ -3031,6 +3264,8 @@ err_stop:
 err_free_netdev:
        for (i--; i >= 0; i--)
                free_netdev(ethsw->ports[i]->netdev);
+       kfree(ethsw->acls);
+err_free_fdbs:
        kfree(ethsw->fdbs);
 err_free_ports:
        kfree(ethsw->ports);
index 0ae1d27..bdef71f 100644 (file)
@@ -18,6 +18,7 @@
 #include <net/switchdev.h>
 #include <linux/if_bridge.h>
 #include <linux/fsl/mc.h>
+#include <net/pkt_cls.h>
 #include <soc/fsl/dpaa2-io.h>
 
 #include "dpsw.h"
@@ -80,6 +81,8 @@
        (DPAA2_SWITCH_TX_DATA_OFFSET + DPAA2_SWITCH_TX_BUF_ALIGN)
 
 #define DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES       16
+#define DPAA2_ETHSW_PORT_DEFAULT_TRAPS         1
+
 #define DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE      256
 
 extern const struct ethtool_ops dpaa2_switch_port_ethtool_ops;
@@ -101,6 +104,34 @@ struct dpaa2_switch_fdb {
        bool                    in_use;
 };
 
+struct dpaa2_switch_acl_entry {
+       struct list_head        list;
+       u16                     prio;
+       unsigned long           cookie;
+
+       struct dpsw_acl_entry_cfg cfg;
+       struct dpsw_acl_key     key;
+};
+
+struct dpaa2_switch_acl_tbl {
+       struct list_head        entries;
+       struct ethsw_core       *ethsw;
+       u64                     ports;
+
+       u16                     id;
+       u8                      num_rules;
+       bool                    in_use;
+};
+
+static inline bool
+dpaa2_switch_acl_tbl_is_full(struct dpaa2_switch_acl_tbl *acl_tbl)
+{
+       if ((acl_tbl->num_rules + DPAA2_ETHSW_PORT_DEFAULT_TRAPS) >=
+           DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES)
+               return true;
+       return false;
+}
+
 /* Per port private data */
 struct ethsw_port_priv {
        struct net_device       *netdev;
@@ -118,8 +149,7 @@ struct ethsw_port_priv {
        bool                    ucast_flood;
        bool                    learn_ena;
 
-       u16                     acl_tbl;
-       u8                      acl_num_rules;
+       struct dpaa2_switch_acl_tbl *acl_tbl;
 };
 
 /* Switch data */
@@ -145,8 +175,21 @@ struct ethsw_core {
        int                             napi_users;
 
        struct dpaa2_switch_fdb         *fdbs;
+       struct dpaa2_switch_acl_tbl     *acls;
 };
 
+static inline int dpaa2_switch_get_index(struct ethsw_core *ethsw,
+                                        struct net_device *netdev)
+{
+       int i;
+
+       for (i = 0; i < ethsw->sw_attr.num_ifs; i++)
+               if (ethsw->ports[i]->netdev == netdev)
+                       return ethsw->ports[i]->idx;
+
+       return -EINVAL;
+}
+
 static inline bool dpaa2_switch_supports_cpu_traffic(struct ethsw_core *ethsw)
 {
        if (ethsw->sw_attr.options & DPSW_OPT_CTRL_IF_DIS) {
@@ -183,4 +226,21 @@ int dpaa2_switch_port_vlans_del(struct net_device *netdev,
 typedef int dpaa2_switch_fdb_cb_t(struct ethsw_port_priv *port_priv,
                                  struct fdb_dump_entry *fdb_entry,
                                  void *data);
+
+/* TC offload */
+
+int dpaa2_switch_cls_flower_replace(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                   struct flow_cls_offload *cls);
+
+int dpaa2_switch_cls_flower_destroy(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                   struct flow_cls_offload *cls);
+
+int dpaa2_switch_cls_matchall_replace(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                     struct tc_cls_matchall_offload *cls);
+
+int dpaa2_switch_cls_matchall_destroy(struct dpaa2_switch_acl_tbl *acl_tbl,
+                                     struct tc_cls_matchall_offload *cls);
+
+int dpaa2_switch_acl_entry_add(struct dpaa2_switch_acl_tbl *acl_tbl,
+                              struct dpaa2_switch_acl_entry *entry);
 #endif /* __ETHSW_H */
index 1747cee..cb13e74 100644 (file)
@@ -77,6 +77,7 @@
 #define DPSW_CMDID_ACL_ADD                  DPSW_CMD_ID(0x090)
 #define DPSW_CMDID_ACL_REMOVE               DPSW_CMD_ID(0x091)
 #define DPSW_CMDID_ACL_ADD_ENTRY            DPSW_CMD_ID(0x092)
+#define DPSW_CMDID_ACL_REMOVE_ENTRY         DPSW_CMD_ID(0x093)
 #define DPSW_CMDID_ACL_ADD_IF               DPSW_CMD_ID(0x094)
 #define DPSW_CMDID_ACL_REMOVE_IF            DPSW_CMD_ID(0x095)
 
index 6704efe..6352d6d 100644 (file)
@@ -1544,3 +1544,38 @@ int dpsw_acl_add_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 
        return mc_send_command(mc_io, &cmd);
 }
+
+/**
+ * dpsw_acl_remove_entry() - Removes an entry from ACL.
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPSW object
+ * @acl_id:    ACL ID
+ * @cfg:       Entry configuration
+ *
+ * warning: This function has to be called after dpsw_acl_set_entry_cfg()
+ *
+ * Return:     '0' on Success; Error code otherwise.
+ */
+int dpsw_acl_remove_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+                         u16 acl_id, const struct dpsw_acl_entry_cfg *cfg)
+{
+       struct dpsw_cmd_acl_entry *cmd_params;
+       struct fsl_mc_command cmd = { 0 };
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_REMOVE_ENTRY,
+                                         cmd_flags,
+                                         token);
+       cmd_params = (struct dpsw_cmd_acl_entry *)cmd.params;
+       cmd_params->acl_id = cpu_to_le16(acl_id);
+       cmd_params->result_if_id = cpu_to_le16(cfg->result.if_id);
+       cmd_params->precedence = cpu_to_le32(cfg->precedence);
+       cmd_params->key_iova = cpu_to_le64(cfg->key_iova);
+       dpsw_set_field(cmd_params->result_action,
+                      RESULT_ACTION,
+                      cfg->result.action);
+
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
+}
index 08e37c4..5ef221a 100644 (file)
@@ -749,4 +749,7 @@ void dpsw_acl_prepare_entry_cfg(const struct dpsw_acl_key *key,
 
 int dpsw_acl_add_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
                       u16 acl_id, const struct dpsw_acl_entry_cfg *cfg);
+
+int dpsw_acl_remove_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+                         u16 acl_id, const struct dpsw_acl_entry_cfg *cfg);
 #endif /* __FSL_DPSW_H */
index f61fedf..30b22b7 100644 (file)
@@ -390,23 +390,54 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
        return 0;
 }
 
-static void enetc_port_setup_primary_mac_address(struct enetc_si *si)
+static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
+                                  int si)
 {
-       unsigned char mac_addr[MAX_ADDR_LEN];
-       struct enetc_pf *pf = enetc_si_priv(si);
-       struct enetc_hw *hw = &si->hw;
-       int i;
+       struct device *dev = &pf->si->pdev->dev;
+       struct enetc_hw *hw = &pf->si->hw;
+       u8 mac_addr[ETH_ALEN] = { 0 };
+       int err;
 
-       /* check MAC addresses for PF and all VFs, if any is 0 set it ro rand */
-       for (i = 0; i < pf->total_vfs + 1; i++) {
-               enetc_pf_get_primary_mac_addr(hw, i, mac_addr);
-               if (!is_zero_ether_addr(mac_addr))
-                       continue;
+       /* (1) try to get the MAC address from the device tree */
+       if (np) {
+               err = of_get_mac_address(np, mac_addr);
+               if (err == -EPROBE_DEFER)
+                       return err;
+       }
+
+       /* (2) bootloader supplied MAC address */
+       if (is_zero_ether_addr(mac_addr))
+               enetc_pf_get_primary_mac_addr(hw, si, mac_addr);
+
+       /* (3) choose a random one */
+       if (is_zero_ether_addr(mac_addr)) {
                eth_random_addr(mac_addr);
-               dev_info(&si->pdev->dev, "no MAC address specified for SI%d, using %pM\n",
-                        i, mac_addr);
-               enetc_pf_set_primary_mac_addr(hw, i, mac_addr);
+               dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
+                        si, mac_addr);
        }
+
+       enetc_pf_set_primary_mac_addr(hw, si, mac_addr);
+
+       return 0;
+}
+
+static int enetc_setup_mac_addresses(struct device_node *np,
+                                    struct enetc_pf *pf)
+{
+       int err, i;
+
+       /* The PF might take its MAC from the device tree */
+       err = enetc_setup_mac_address(np, pf, 0);
+       if (err)
+               return err;
+
+       for (i = 0; i < pf->total_vfs; i++) {
+               err = enetc_setup_mac_address(NULL, pf, i + 1);
+               if (err)
+                       return err;
+       }
+
+       return 0;
 }
 
 static void enetc_port_assign_rfs_entries(struct enetc_si *si)
@@ -562,9 +593,6 @@ static void enetc_configure_port(struct enetc_pf *pf)
        /* split up RFS entries */
        enetc_port_assign_rfs_entries(pf->si);
 
-       /* fix-up primary MAC addresses, if not set already */
-       enetc_port_setup_primary_mac_address(pf->si);
-
        /* enforce VLAN promisc mode for all SIs */
        pf->vlan_promisc_simap = ENETC_VLAN_PROMISC_MAP_ALL;
        enetc_set_vlan_promisc(hw, pf->vlan_promisc_simap);
@@ -1137,6 +1165,10 @@ static int enetc_pf_probe(struct pci_dev *pdev,
        pf->si = si;
        pf->total_vfs = pci_sriov_get_totalvfs(pdev);
 
+       err = enetc_setup_mac_addresses(node, pf);
+       if (err)
+               goto err_setup_mac_addresses;
+
        enetc_configure_port(pf);
 
        enetc_get_si_caps(si);
@@ -1204,6 +1236,7 @@ err_alloc_netdev:
 err_init_port_rss:
 err_init_port_rfs:
 err_device_disabled:
+err_setup_mac_addresses:
        enetc_teardown_cbdr(&si->cbd_ring);
 err_setup_cbdr:
 err_map_pf_space:
index 70aea9c..aecc111 100644 (file)
@@ -1665,6 +1665,7 @@ static void fec_get_mac(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
        unsigned char *iap, tmpaddr[ETH_ALEN];
+       int ret;
 
        /*
         * try to get mac address in following order:
@@ -1680,9 +1681,9 @@ static void fec_get_mac(struct net_device *ndev)
        if (!is_valid_ether_addr(iap)) {
                struct device_node *np = fep->pdev->dev.of_node;
                if (np) {
-                       const char *mac = of_get_mac_address(np);
-                       if (!IS_ERR(mac))
-                               iap = (unsigned char *) mac;
+                       ret = of_get_mac_address(np, tmpaddr);
+                       if (!ret)
+                               iap = tmpaddr;
                }
        }
 
index b3bad42..02c4765 100644 (file)
@@ -813,7 +813,6 @@ static int mpc52xx_fec_probe(struct platform_device *op)
        const u32 *prop;
        int prop_size;
        struct device_node *np = op->dev.of_node;
-       const char *mac_addr;
 
        phys_addr_t rx_fifo;
        phys_addr_t tx_fifo;
@@ -891,10 +890,8 @@ static int mpc52xx_fec_probe(struct platform_device *op)
         *
         * First try to read MAC address from DT
         */
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr)) {
-               ether_addr_copy(ndev->dev_addr, mac_addr);
-       } else {
+       rv = of_get_mac_address(np, ndev->dev_addr);
+       if (rv) {
                struct mpc52xx_fec __iomem *fec = priv->fec;
 
                /*
index 901749a..46ecb42 100644 (file)
@@ -605,7 +605,6 @@ static int mac_probe(struct platform_device *_of_dev)
        struct platform_device  *of_dev;
        struct resource          res;
        struct mac_priv_s       *priv;
-       const u8                *mac_addr;
        u32                      val;
        u8                      fman_id;
        phy_interface_t          phy_if;
@@ -723,11 +722,9 @@ static int mac_probe(struct platform_device *_of_dev)
        priv->cell_index = (u8)val;
 
        /* Get the MAC address */
-       mac_addr = of_get_mac_address(mac_node);
-       if (IS_ERR(mac_addr))
+       err = of_get_mac_address(mac_node, mac_dev->addr);
+       if (err)
                dev_warn(dev, "of_get_mac_address(%pOF) failed\n", mac_node);
-       else
-               ether_addr_copy(mac_dev->addr, mac_addr);
 
        /* Get the port handles */
        nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);
@@ -853,7 +850,7 @@ static int mac_probe(struct platform_device *_of_dev)
        if (err < 0)
                dev_err(dev, "fman_set_mac_active_pause() = %d\n", err);
 
-       if (!IS_ERR(mac_addr))
+       if (!is_zero_ether_addr(mac_dev->addr))
                dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
 
        priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev);
index 78e008b..6ee325a 100644 (file)
@@ -918,7 +918,6 @@ static int fs_enet_probe(struct platform_device *ofdev)
        const u32 *data;
        struct clk *clk;
        int err;
-       const u8 *mac_addr;
        const char *phy_connection_type;
        int privsize, len, ret = -ENODEV;
 
@@ -1006,9 +1005,7 @@ static int fs_enet_probe(struct platform_device *ofdev)
        spin_lock_init(&fep->lock);
        spin_lock_init(&fep->tx_lock);
 
-       mac_addr = of_get_mac_address(ofdev->dev.of_node);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(ndev->dev_addr, mac_addr);
+       of_get_mac_address(ofdev->dev.of_node, ndev->dev_addr);
 
        ret = fep->ops->allocate_bd(ndev);
        if (ret)
index 3ec4d9f..339f956 100644 (file)
@@ -640,7 +640,6 @@ static phy_interface_t gfar_get_interface(struct net_device *dev)
 static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 {
        const char *model;
-       const void *mac_addr;
        int err = 0, i;
        phy_interface_t interface;
        struct net_device *dev = NULL;
@@ -782,11 +781,8 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
        if (stash_len || stash_idx)
                priv->device_flags |= FSL_GIANFAR_DEV_HAS_BUF_STASHING;
 
-       mac_addr = of_get_mac_address(np);
-
-       if (!IS_ERR(mac_addr)) {
-               ether_addr_copy(dev->dev_addr, mac_addr);
-       } else {
+       err = of_get_mac_address(np, dev->dev_addr);
+       if (err) {
                eth_hw_addr_random(dev);
                dev_info(&ofdev->dev, "Using random MAC address: %pM\n", dev->dev_addr);
        }
index ef4e2fe..e093651 100644 (file)
@@ -3562,7 +3562,6 @@ static int ucc_geth_probe(struct platform_device* ofdev)
        struct resource res;
        int err, ucc_num, max_speed = 0;
        const unsigned int *prop;
-       const void *mac_addr;
        phy_interface_t phy_interface;
        static const int enet_to_speed[] = {
                SPEED_10, SPEED_10, SPEED_10,
@@ -3733,9 +3732,7 @@ static int ucc_geth_probe(struct platform_device* ofdev)
                goto err_free_netdev;
        }
 
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(dev->dev_addr, mac_addr);
+       of_get_mac_address(np, dev->dev_addr);
 
        ugeth->ug_info = ug_info;
        ugeth->dev = device;
index 57c3bc4..3c4db4a 100644 (file)
@@ -772,7 +772,6 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
        struct net_device *ndev;
        struct hisi_femac_priv *priv;
        struct phy_device *phy;
-       const char *mac_addr;
        int ret;
 
        ndev = alloc_etherdev(sizeof(*priv));
@@ -842,10 +841,8 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
                           (unsigned long)phy->phy_id,
                           phy_modes(phy->interface));
 
-       mac_addr = of_get_mac_address(node);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(ndev->dev_addr, mac_addr);
-       if (!is_valid_ether_addr(ndev->dev_addr)) {
+       ret = of_get_mac_address(node, ndev->dev_addr);
+       if (ret) {
                eth_hw_addr_random(ndev);
                dev_warn(dev, "using random MAC address %pM\n",
                         ndev->dev_addr);
index 8b2bf85..c1aae0f 100644 (file)
@@ -1098,7 +1098,6 @@ static int hix5hd2_dev_probe(struct platform_device *pdev)
        struct net_device *ndev;
        struct hix5hd2_priv *priv;
        struct mii_bus *bus;
-       const char *mac_addr;
        int ret;
 
        ndev = alloc_etherdev(sizeof(struct hix5hd2_priv));
@@ -1220,10 +1219,8 @@ static int hix5hd2_dev_probe(struct platform_device *pdev)
                goto out_phy_node;
        }
 
-       mac_addr = of_get_mac_address(node);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(ndev->dev_addr, mac_addr);
-       if (!is_valid_ether_addr(ndev->dev_addr)) {
+       ret = of_get_mac_address(node, ndev->dev_addr);
+       if (ret) {
                eth_hw_addr_random(ndev);
                netdev_warn(ndev, "using random MAC address %pM\n",
                            ndev->dev_addr);
index ee9bf18..b72159c 100644 (file)
@@ -2292,8 +2292,9 @@ static void __ibmvnic_reset(struct work_struct *work)
        adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
 
        if (test_and_set_bit_lock(0, &adapter->resetting)) {
-               schedule_delayed_work(&adapter->ibmvnic_delayed_reset,
-                                     IBMVNIC_RESET_DELAY);
+               queue_delayed_work(system_long_wq,
+                                  &adapter->ibmvnic_delayed_reset,
+                                  IBMVNIC_RESET_DELAY);
                return;
        }
 
@@ -2437,7 +2438,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
        list_add_tail(&rwi->list, &adapter->rwi_list);
        netdev_dbg(adapter->netdev, "Scheduling reset (reason %s)\n",
                   reset_reason_to_string(reason));
-       schedule_work(&adapter->ibmvnic_reset);
+       queue_work(system_long_wq, &adapter->ibmvnic_reset);
 
        ret = 0;
 err:
@@ -5503,7 +5504,7 @@ static ssize_t failover_store(struct device *dev, struct device_attribute *attr,
        if (rc) {
                netdev_err(netdev, "Couldn't retrieve session token, rc %ld\n",
                           rc);
-               return -EINVAL;
+               goto last_resort;
        }
 
        session_token = (__be64)retbuf[0];
@@ -5511,15 +5512,17 @@ static ssize_t failover_store(struct device *dev, struct device_attribute *attr,
                   be64_to_cpu(session_token));
        rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address,
                                H_SESSION_ERR_DETECTED, session_token, 0, 0);
-       if (rc) {
-               netdev_err(netdev, "Client initiated failover failed, rc %ld\n",
+       if (rc)
+               netdev_err(netdev,
+                          "H_VIOCTL initiated failover failed, rc %ld\n",
                           rc);
-               return -EINVAL;
-       }
+
+last_resort:
+       netdev_dbg(netdev, "Trying to send CRQ_CMD, the last resort\n");
+       ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
 
        return count;
 }
-
 static DEVICE_ATTR_WO(failover);
 
 static unsigned long ibmvnic_get_desired_dma(struct vio_dev *vdev)
index c00332d..72e6ebf 100644 (file)
@@ -361,7 +361,7 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
        }
 
 #ifdef IXGBE_FCOE
-       /* Reprogam FCoE hardware offloads when the traffic class
+       /* Reprogram FCoE hardware offloads when the traffic class
         * FCoE is using changes. This happens if the APP info
         * changes or the up2tc mapping is updated.
         */
index 73bc170..24aa97f 100644 (file)
@@ -380,6 +380,9 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
        case X557_PHY_ID2:
                phy_type = ixgbe_phy_x550em_ext_t;
                break;
+       case BCM54616S_E_PHY_ID:
+               phy_type = ixgbe_phy_ext_1g_t;
+               break;
        default:
                phy_type = ixgbe_phy_unknown;
                break;
index 2be1c4c..2647937 100644 (file)
@@ -1407,6 +1407,7 @@ struct ixgbe_nvm_version {
 #define QT2022_PHY_ID    0x0043A400
 #define ATH_PHY_ID       0x03429050
 #define AQ_FW_REV        0x20
+#define BCM54616S_E_PHY_ID 0x03625D10
 
 /* Special PHY Init Routine */
 #define IXGBE_PHY_INIT_OFFSET_NL 0x002B
@@ -3383,10 +3384,6 @@ struct ixgbe_hw_stats {
 /* forward declaration */
 struct ixgbe_hw;
 
-/* iterator type for walking multicast address lists */
-typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr,
-                                 u32 *vmdq);
-
 /* Function pointer table */
 struct ixgbe_eeprom_operations {
        s32 (*init_params)(struct ixgbe_hw *);
index d1e9e30..1d8209d 100644 (file)
@@ -16,9 +16,6 @@
 
 struct ixgbe_hw;
 
-/* iterator type for walking multicast address lists */
-typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr,
-                                 u32 *vmdq);
 struct ixgbe_mac_operations {
        s32 (*init_hw)(struct ixgbe_hw *);
        s32 (*reset_hw)(struct ixgbe_hw *);
index 0f8ef8f..41c2ad2 100644 (file)
@@ -435,7 +435,6 @@ static int xrx200_probe(struct platform_device *pdev)
        struct resource *res;
        struct xrx200_priv *priv;
        struct net_device *net_dev;
-       const u8 *mac;
        int err;
 
        /* alloc the network device */
@@ -477,10 +476,8 @@ static int xrx200_probe(struct platform_device *pdev)
                return PTR_ERR(priv->clk);
        }
 
-       mac = of_get_mac_address(np);
-       if (!IS_ERR(mac))
-               ether_addr_copy(net_dev->dev_addr, mac);
-       else
+       err = of_get_mac_address(np, net_dev->dev_addr);
+       if (err)
                eth_hw_addr_random(net_dev);
 
        /* bring up the dma engine and IP core */
index ca1681a..d207bfc 100644 (file)
@@ -2702,7 +2702,6 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
        struct platform_device *ppdev;
        struct mv643xx_eth_platform_data ppd;
        struct resource res;
-       const char *mac_addr;
        int ret;
        int dev_num = 0;
 
@@ -2733,9 +2732,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
                return -EINVAL;
        }
 
-       mac_addr = of_get_mac_address(pnp);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(ppd.mac_addr, mac_addr);
+       of_get_mac_address(pnp, ppd.mac_addr);
 
        mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size);
        mv643xx_eth_property(pnp, "tx-sram-addr", ppd.tx_sram_addr);
index f20dfd1..7d5cd9b 100644 (file)
@@ -5141,7 +5141,6 @@ static int mvneta_probe(struct platform_device *pdev)
        struct net_device *dev;
        struct phylink *phylink;
        struct phy *comphy;
-       const char *dt_mac_addr;
        char hw_mac_addr[ETH_ALEN];
        phy_interface_t phy_mode;
        const char *mac_from;
@@ -5237,10 +5236,9 @@ static int mvneta_probe(struct platform_device *pdev)
                goto err_free_ports;
        }
 
-       dt_mac_addr = of_get_mac_address(dn);
-       if (!IS_ERR(dt_mac_addr)) {
+       err = of_get_mac_address(dn, dev->dev_addr);
+       if (!err) {
                mac_from = "device tree";
-               ether_addr_copy(dev->dev_addr, dt_mac_addr);
        } else {
                mvneta_get_mac_addr(pp, hw_mac_addr);
                if (is_valid_ether_addr(hw_mac_addr)) {
index 25dd903..f08c420 100644 (file)
@@ -456,20 +456,17 @@ static int prestera_switch_set_base_mac_addr(struct prestera_switch *sw)
 {
        struct device_node *base_mac_np;
        struct device_node *np;
-       const char *base_mac;
+       int ret;
 
        np = of_find_compatible_node(NULL, NULL, "marvell,prestera");
        base_mac_np = of_parse_phandle(np, "base-mac-provider", 0);
 
-       base_mac = of_get_mac_address(base_mac_np);
-       of_node_put(base_mac_np);
-       if (!IS_ERR(base_mac))
-               ether_addr_copy(sw->base_mac, base_mac);
-
-       if (!is_valid_ether_addr(sw->base_mac)) {
+       ret = of_get_mac_address(base_mac_np, sw->base_mac);
+       if (ret) {
                eth_random_addr(sw->base_mac);
                dev_info(prestera_dev(sw), "using random base mac address\n");
        }
+       of_node_put(base_mac_np);
 
        return prestera_hw_switch_mac_set(sw, sw->base_mac);
 }
index 3712e17..e967867 100644 (file)
@@ -1392,7 +1392,6 @@ static int pxa168_eth_probe(struct platform_device *pdev)
        struct resource *res;
        struct clk *clk;
        struct device_node *np;
-       const unsigned char *mac_addr = NULL;
        int err;
 
        printk(KERN_NOTICE "PXA168 10/100 Ethernet Driver\n");
@@ -1435,12 +1434,8 @@ static int pxa168_eth_probe(struct platform_device *pdev)
 
        INIT_WORK(&pep->tx_timeout_task, pxa168_eth_tx_timeout_task);
 
-       if (pdev->dev.of_node)
-               mac_addr = of_get_mac_address(pdev->dev.of_node);
-
-       if (!IS_ERR_OR_NULL(mac_addr)) {
-               ether_addr_copy(dev->dev_addr, mac_addr);
-       } else {
+       err = of_get_mac_address(pdev->dev.of_node, dev->dev_addr);
+       if (err) {
                /* try reading the mac address, if set by the bootloader */
                pxa168_eth_get_mac_address(dev, dev->dev_addr);
                if (!is_valid_ether_addr(dev->dev_addr)) {
index 68c154d..222c323 100644 (file)
@@ -4728,7 +4728,7 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
 {
        struct sky2_port *sky2;
        struct net_device *dev = alloc_etherdev(sizeof(*sky2));
-       const void *iap;
+       int ret;
 
        if (!dev)
                return NULL;
@@ -4798,10 +4798,8 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
         * 1) from device tree data
         * 2) from internal registers set by bootloader
         */
-       iap = of_get_mac_address(hw->pdev->dev.of_node);
-       if (!IS_ERR(iap))
-               ether_addr_copy(dev->dev_addr, iap);
-       else
+       ret = of_get_mac_address(hw->pdev->dev.of_node, dev->dev_addr);
+       if (ret)
                memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8,
                              ETH_ALEN);
 
index 810def0..6b00c12 100644 (file)
@@ -2484,14 +2484,11 @@ static int __init mtk_init(struct net_device *dev)
 {
        struct mtk_mac *mac = netdev_priv(dev);
        struct mtk_eth *eth = mac->hw;
-       const char *mac_addr;
-
-       mac_addr = of_get_mac_address(mac->of_node);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(dev->dev_addr, mac_addr);
+       int ret;
 
-       /* If the mac address is invalid, use random mac address  */
-       if (!is_valid_ether_addr(dev->dev_addr)) {
+       ret = of_get_mac_address(mac->of_node, dev->dev_addr);
+       if (ret) {
+               /* If the mac address is invalid, use random mac address */
                eth_hw_addr_random(dev);
                dev_err(eth->dev, "generated random MAC address %pM\n",
                        dev->dev_addr);
index 2feed6c..13eef6e 100644 (file)
@@ -193,11 +193,10 @@ static void ks8851_read_mac_addr(struct net_device *dev)
 static void ks8851_init_mac(struct ks8851_net *ks, struct device_node *np)
 {
        struct net_device *dev = ks->netdev;
-       const u8 *mac_addr;
+       int ret;
 
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr)) {
-               ether_addr_copy(dev->dev_addr, mac_addr);
+       ret = of_get_mac_address(np, dev->dev_addr);
+       if (!ret) {
                ks8851_write_mac_addr(dev);
                return;
        }
index 11a1dc4..dae1032 100644 (file)
@@ -2771,7 +2771,6 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
 {
        struct lan743x_adapter *adapter = NULL;
        struct net_device *netdev = NULL;
-       const void *mac_addr;
        int ret = -ENODEV;
 
        netdev = devm_alloc_etherdev(&pdev->dev,
@@ -2788,9 +2787,7 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
                              NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
        netdev->max_mtu = LAN743X_MAX_FRAME_SIZE;
 
-       mac_addr = of_get_mac_address(pdev->dev.of_node);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(adapter->mac_address, mac_addr);
+       of_get_mac_address(pdev->dev.of_node, adapter->mac_address);
 
        ret = lan743x_pci_init(adapter, pdev);
        if (ret)
index e72fd33..64c6842 100644 (file)
@@ -1350,9 +1350,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
        __lpc_get_mac(pldat, ndev->dev_addr);
 
        if (!is_valid_ether_addr(ndev->dev_addr)) {
-               const char *macaddr = of_get_mac_address(np);
-               if (!IS_ERR(macaddr))
-                       ether_addr_copy(ndev->dev_addr, macaddr);
+               of_get_mac_address(np, ndev->dev_addr);
        }
        if (!is_valid_ether_addr(ndev->dev_addr))
                eth_hw_addr_random(ndev);
index 71db1e2..6583be5 100644 (file)
@@ -888,55 +888,55 @@ static int ionic_get_ts_info(struct net_device *netdev,
 
        mask = cpu_to_le64(IONIC_PKT_CLS_NTP_ALL);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_NTP_ALL;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_NTP_ALL);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_SYNC);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_DREQ);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_ALL);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_SYNC);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_L4_SYNC;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_DREQ);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_ALL);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_SYNC);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_L2_SYNC;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_DREQ);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_ALL);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_SYNC);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_SYNC;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_SYNC);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_DREQ);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
 
        mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_ALL);
        if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
-               info->rx_filters |= HWTSTAMP_FILTER_PTP_V2_EVENT;
+               info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
 
        return 0;
 }
index 177dbf8..a87c87e 100644 (file)
@@ -225,7 +225,9 @@ int ionic_lif_hwstamp_get(struct ionic_lif *lif, struct ifreq *ifr)
        memcpy(&config, &lif->phc->ts_config, sizeof(config));
        mutex_unlock(&lif->phc->config_lock);
 
-       return copy_to_user(ifr->ifr_data, &config, sizeof(config));
+       if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
+               return -EFAULT;
+       return 0;
 }
 
 static u64 ionic_hwstamp_read(struct ionic *ionic,
index 5a3b65a..ab9b025 100644 (file)
@@ -885,7 +885,7 @@ qca_spi_probe(struct spi_device *spi)
        struct net_device *qcaspi_devs = NULL;
        u8 legacy_mode = 0;
        u16 signature;
-       const char *mac;
+       int ret;
 
        if (!spi->dev.of_node) {
                dev_err(&spi->dev, "Missing device tree\n");
@@ -962,12 +962,8 @@ qca_spi_probe(struct spi_device *spi)
 
        spi_set_drvdata(spi, qcaspi_devs);
 
-       mac = of_get_mac_address(spi->dev.of_node);
-
-       if (!IS_ERR(mac))
-               ether_addr_copy(qca->net_dev->dev_addr, mac);
-
-       if (!is_valid_ether_addr(qca->net_dev->dev_addr)) {
+       ret = of_get_mac_address(spi->dev.of_node, qca->net_dev->dev_addr);
+       if (ret) {
                eth_hw_addr_random(qca->net_dev);
                dev_info(&spi->dev, "Using random MAC address: %pM\n",
                         qca->net_dev->dev_addr);
index 362b4f5..bcdeca7 100644 (file)
@@ -323,7 +323,6 @@ static int qca_uart_probe(struct serdev_device *serdev)
 {
        struct net_device *qcauart_dev = alloc_etherdev(sizeof(struct qcauart));
        struct qcauart *qca;
-       const char *mac;
        u32 speed = 115200;
        int ret;
 
@@ -348,12 +347,8 @@ static int qca_uart_probe(struct serdev_device *serdev)
 
        of_property_read_u32(serdev->dev.of_node, "current-speed", &speed);
 
-       mac = of_get_mac_address(serdev->dev.of_node);
-
-       if (!IS_ERR(mac))
-               ether_addr_copy(qca->net_dev->dev_addr, mac);
-
-       if (!is_valid_ether_addr(qca->net_dev->dev_addr)) {
+       ret = of_get_mac_address(serdev->dev.of_node, qca->net_dev->dev_addr);
+       if (ret) {
                eth_hw_addr_random(qca->net_dev);
                dev_info(&serdev->dev, "Using random MAC address: %pM\n",
                         qca->net_dev->dev_addr);
index 85031b4..9856773 100644 (file)
@@ -1910,6 +1910,32 @@ static void rtl8169_get_ringparam(struct net_device *dev,
        data->tx_pending = NUM_TX_DESC;
 }
 
+static void rtl8169_get_pauseparam(struct net_device *dev,
+                                  struct ethtool_pauseparam *data)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       bool tx_pause, rx_pause;
+
+       phy_get_pause(tp->phydev, &tx_pause, &rx_pause);
+
+       data->autoneg = tp->phydev->autoneg;
+       data->tx_pause = tx_pause ? 1 : 0;
+       data->rx_pause = rx_pause ? 1 : 0;
+}
+
+static int rtl8169_set_pauseparam(struct net_device *dev,
+                                 struct ethtool_pauseparam *data)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+
+       if (dev->mtu > ETH_DATA_LEN)
+               return -EOPNOTSUPP;
+
+       phy_set_asym_pause(tp->phydev, data->rx_pause, data->tx_pause);
+
+       return 0;
+}
+
 static const struct ethtool_ops rtl8169_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
                                     ETHTOOL_COALESCE_MAX_FRAMES,
@@ -1931,6 +1957,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
        .get_link_ksettings     = phy_ethtool_get_link_ksettings,
        .set_link_ksettings     = phy_ethtool_set_link_ksettings,
        .get_ringparam          = rtl8169_get_ringparam,
+       .get_pauseparam         = rtl8169_get_pauseparam,
+       .set_pauseparam         = rtl8169_set_pauseparam,
 };
 
 static void rtl_enable_eee(struct rtl8169_private *tp)
index 1409ae9..8c84c40 100644 (file)
@@ -109,11 +109,13 @@ static void ravb_set_buffer_align(struct sk_buff *skb)
  * Ethernet AVB device doesn't have ROM for MAC address.
  * This function gets the MAC address that was used by a bootloader.
  */
-static void ravb_read_mac_address(struct net_device *ndev, const u8 *mac)
+static void ravb_read_mac_address(struct device_node *np,
+                                 struct net_device *ndev)
 {
-       if (!IS_ERR(mac)) {
-               ether_addr_copy(ndev->dev_addr, mac);
-       } else {
+       int ret;
+
+       ret = of_get_mac_address(np, ndev->dev_addr);
+       if (ret) {
                u32 mahr = ravb_read(ndev, MAHR);
                u32 malr = ravb_read(ndev, MALR);
 
@@ -2207,7 +2209,7 @@ static int ravb_probe(struct platform_device *pdev)
        priv->msg_enable = RAVB_DEF_MSG_ENABLE;
 
        /* Read and set MAC address */
-       ravb_read_mac_address(ndev, of_get_mac_address(np));
+       ravb_read_mac_address(np, ndev);
        if (!is_valid_ether_addr(ndev->dev_addr)) {
                dev_warn(&pdev->dev,
                         "no valid MAC address supplied, using a random one\n");
index ebedb1a..c5b1548 100644 (file)
@@ -3170,7 +3170,6 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
        struct device_node *np = dev->of_node;
        struct sh_eth_plat_data *pdata;
        phy_interface_t interface;
-       const char *mac_addr;
        int ret;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -3182,9 +3181,7 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
                return NULL;
        pdata->phy_interface = interface;
 
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(pdata->mac_addr, mac_addr);
+       of_get_mac_address(np, pdata->mac_addr);
 
        pdata->no_ether_link =
                of_property_read_bool(np, "renesas,no-ether-link");
index 33f7940..4639ed9 100644 (file)
@@ -25,8 +25,7 @@
 
 #ifdef CONFIG_OF
 static int sxgbe_probe_config_dt(struct platform_device *pdev,
-                                struct sxgbe_plat_data *plat,
-                                const char **mac)
+                                struct sxgbe_plat_data *plat)
 {
        struct device_node *np = pdev->dev.of_node;
        struct sxgbe_dma_cfg *dma_cfg;
@@ -35,7 +34,6 @@ static int sxgbe_probe_config_dt(struct platform_device *pdev,
        if (!np)
                return -ENODEV;
 
-       *mac = of_get_mac_address(np);
        err = of_get_phy_mode(np, &plat->interface);
        if (err && err != -ENODEV)
                return err;
@@ -63,8 +61,7 @@ static int sxgbe_probe_config_dt(struct platform_device *pdev,
 }
 #else
 static int sxgbe_probe_config_dt(struct platform_device *pdev,
-                                struct sxgbe_plat_data *plat,
-                                const char **mac)
+                                struct sxgbe_plat_data *plat)
 {
        return -ENOSYS;
 }
@@ -85,7 +82,6 @@ static int sxgbe_platform_probe(struct platform_device *pdev)
        void __iomem *addr;
        struct sxgbe_priv_data *priv = NULL;
        struct sxgbe_plat_data *plat_dat = NULL;
-       const char *mac = NULL;
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct device_node *node = dev->of_node;
 
@@ -101,7 +97,7 @@ static int sxgbe_platform_probe(struct platform_device *pdev)
                if (!plat_dat)
                        return  -ENOMEM;
 
-               ret = sxgbe_probe_config_dt(pdev, plat_dat, &mac);
+               ret = sxgbe_probe_config_dt(pdev, plat_dat);
                if (ret) {
                        pr_err("%s: main dt probe failed\n", __func__);
                        return ret;
@@ -122,8 +118,7 @@ static int sxgbe_platform_probe(struct platform_device *pdev)
        }
 
        /* Get MAC address if available (DT) */
-       if (!IS_ERR_OR_NULL(mac))
-               ether_addr_copy(priv->dev->dev_addr, mac);
+       of_get_mac_address(node, priv->dev->dev_addr);
 
        /* Get the TX/RX IRQ numbers */
        for (i = 0, chan = 1; i < SXGBE_TX_QUEUES; i++) {
index 3332cdf..cd590e0 100644 (file)
@@ -78,7 +78,6 @@ enum efx_loopback_mode {
                            (1 << LOOPBACK_XAUI) |              \
                            (1 << LOOPBACK_GMII) |              \
                            (1 << LOOPBACK_SGMII) |             \
-                           (1 << LOOPBACK_SGMII) |             \
                            (1 << LOOPBACK_XGBR) |              \
                            (1 << LOOPBACK_XFI) |               \
                            (1 << LOOPBACK_XAUI_FAR) |          \
index 501b9c7..fcbb4bb 100644 (file)
@@ -1559,7 +1559,6 @@ static int ave_probe(struct platform_device *pdev)
        struct ave_private *priv;
        struct net_device *ndev;
        struct device_node *np;
-       const void *mac_addr;
        void __iomem *base;
        const char *name;
        int i, irq, ret;
@@ -1600,12 +1599,9 @@ static int ave_probe(struct platform_device *pdev)
 
        ndev->max_mtu = AVE_MAX_ETHFRAME - (ETH_HLEN + ETH_FCS_LEN);
 
-       mac_addr = of_get_mac_address(np);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(ndev->dev_addr, mac_addr);
-
-       /* if the mac address is invalid, use random mac address */
-       if (!is_valid_ether_addr(ndev->dev_addr)) {
+       ret = of_get_mac_address(np, ndev->dev_addr);
+       if (ret) {
+               /* if the mac address is invalid, use random mac address */
                eth_hw_addr_random(ndev);
                dev_warn(dev, "Using random MAC address: %pM\n",
                         ndev->dev_addr);
index 08c7663..dfbaea0 100644 (file)
@@ -115,7 +115,7 @@ static int anarion_dwmac_probe(struct platform_device *pdev)
        if (IS_ERR(gmac))
                return PTR_ERR(gmac);
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 27254b2..bc91fd8 100644 (file)
@@ -438,7 +438,7 @@ static int dwc_eth_dwmac_probe(struct platform_device *pdev)
        if (IS_ERR(stmmac_res.addr))
                return PTR_ERR(stmmac_res.addr);
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index fad5038..fbfda55 100644 (file)
@@ -27,7 +27,7 @@ static int dwmac_generic_probe(struct platform_device *pdev)
                return ret;
 
        if (pdev->dev.of_node) {
-               plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+               plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
                if (IS_ERR(plat_dat)) {
                        dev_err(&pdev->dev, "dt configuration failed\n");
                        return PTR_ERR(plat_dat);
index c1a3613..8465120 100644 (file)
@@ -231,7 +231,7 @@ static int imx_dwmac_probe(struct platform_device *pdev)
        if (!dwmac)
                return -ENOMEM;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 6c19fcc..06d287f 100644 (file)
@@ -85,7 +85,7 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat)) {
                dev_err(&pdev->dev, "dt configuration failed\n");
                return PTR_ERR(plat_dat);
index 6056659..ec140fc 100644 (file)
@@ -296,6 +296,13 @@ static int intel_crosststamp(ktime_t *device,
 
        intel_priv = priv->plat->bsp_priv;
 
+       /* Both internal crosstimestamping and external triggered event
+        * timestamping cannot be run concurrently.
+        */
+       if (priv->plat->ext_snapshot_en)
+               return -EBUSY;
+
+       mutex_lock(&priv->aux_ts_lock);
        /* Enable Internal snapshot trigger */
        acr_value = readl(ptpaddr + PTP_ACR);
        acr_value &= ~PTP_ACR_MASK;
@@ -321,6 +328,8 @@ static int intel_crosststamp(ktime_t *device,
        acr_value = readl(ptpaddr + PTP_ACR);
        acr_value |= PTP_ACR_ATSFC;
        writel(acr_value, ptpaddr + PTP_ACR);
+       /* Release the mutex */
+       mutex_unlock(&priv->aux_ts_lock);
 
        /* Trigger Internal snapshot signal
         * Create a rising edge by just toggle the GPO1 to low
@@ -520,6 +529,7 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
        plat->mdio_bus_data->phy_mask |= 1 << INTEL_MGBE_XPCS_ADDR;
 
        plat->int_snapshot_num = AUX_SNAPSHOT1;
+       plat->ext_snapshot_num = AUX_SNAPSHOT0;
 
        plat->has_crossts = true;
        plat->crosststamp = intel_crosststamp;
index 749585f..28dd0ed 100644 (file)
@@ -255,7 +255,7 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
        if (val)
                return val;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 3d3f43d..9d77c64 100644 (file)
@@ -37,7 +37,7 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 9e4b838..58c0fea 100644 (file)
@@ -407,7 +407,7 @@ static int mediatek_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index bbc16b5..16fb66a 100644 (file)
@@ -52,7 +52,7 @@ static int meson6_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 848e5c3..c7a6588 100644 (file)
@@ -398,7 +398,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 8551ea8..adfeb8d 100644 (file)
@@ -118,7 +118,7 @@ static int oxnas_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index a674b7d..84382fc 100644 (file)
@@ -461,7 +461,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat)) {
                dev_err(&pdev->dev, "dt configuration failed\n");
                return PTR_ERR(plat_dat);
index 6ef3025..8d28a53 100644 (file)
@@ -1396,7 +1396,7 @@ static int rk_gmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 70d4178..8520812 100644 (file)
@@ -398,7 +398,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index e1b63df..710d743 100644 (file)
@@ -325,7 +325,7 @@ static int sti_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 5d4df4c..2b38a49 100644 (file)
@@ -371,7 +371,7 @@ static int stm32_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 19e7ec3..4422bae 100644 (file)
@@ -1221,7 +1221,7 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return -EINVAL;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 0e1ca2c..527077c 100644 (file)
@@ -108,7 +108,7 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index d23be45..d046e33 100644 (file)
@@ -208,7 +208,7 @@ static int visconti_eth_dwmac_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+       plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
index 2b5022e..2cc9175 100644 (file)
@@ -504,6 +504,8 @@ struct stmmac_ops {
 #define stmmac_fpe_irq_status(__priv, __args...) \
        stmmac_do_callback(__priv, mac, fpe_irq_status, __args)
 
+struct stmmac_priv;
+
 /* PTP and HW Timer helpers */
 struct stmmac_hwtimestamp {
        void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
@@ -515,6 +517,7 @@ struct stmmac_hwtimestamp {
                               int add_sub, int gmac4);
        void (*get_systime) (void __iomem *ioaddr, u64 *systime);
        void (*get_ptptime)(void __iomem *ioaddr, u64 *ptp_time);
+       void (*timestamp_interrupt)(struct stmmac_priv *priv);
 };
 
 #define stmmac_config_hw_tstamping(__priv, __args...) \
@@ -531,6 +534,8 @@ struct stmmac_hwtimestamp {
        stmmac_do_void_callback(__priv, ptp, get_systime, __args)
 #define stmmac_get_ptptime(__priv, __args...) \
        stmmac_do_void_callback(__priv, ptp, get_ptptime, __args)
+#define stmmac_timestamp_interrupt(__priv, __args...) \
+       stmmac_do_void_callback(__priv, ptp, timestamp_interrupt, __args)
 
 /* Helpers to manage the descriptors for chain and ring modes */
 struct stmmac_mode_ops {
index c49debb..b6cd43e 100644 (file)
@@ -26,7 +26,7 @@
 
 struct stmmac_resources {
        void __iomem *addr;
-       const char *mac;
+       u8 mac[ETH_ALEN];
        int wol_irq;
        int lpi_irq;
        int irq;
@@ -40,6 +40,7 @@ enum stmmac_txbuf_type {
        STMMAC_TXBUF_T_SKB,
        STMMAC_TXBUF_T_XDP_TX,
        STMMAC_TXBUF_T_XDP_NDO,
+       STMMAC_TXBUF_T_XSK_TX,
 };
 
 struct stmmac_tx_info {
@@ -69,6 +70,8 @@ struct stmmac_tx_queue {
                struct xdp_frame **xdpf;
        };
        struct stmmac_tx_info *tx_skbuff_dma;
+       struct xsk_buff_pool *xsk_pool;
+       u32 xsk_frames_done;
        unsigned int cur_tx;
        unsigned int dirty_tx;
        dma_addr_t dma_tx_phy;
@@ -77,9 +80,14 @@ struct stmmac_tx_queue {
 };
 
 struct stmmac_rx_buffer {
-       struct page *page;
-       dma_addr_t addr;
-       __u32 page_offset;
+       union {
+               struct {
+                       struct page *page;
+                       dma_addr_t addr;
+                       __u32 page_offset;
+               };
+               struct xdp_buff *xdp;
+       };
        struct page *sec_page;
        dma_addr_t sec_addr;
 };
@@ -88,6 +96,7 @@ struct stmmac_rx_queue {
        u32 rx_count_frames;
        u32 queue_index;
        struct xdp_rxq_info xdp_rxq;
+       struct xsk_buff_pool *xsk_pool;
        struct page_pool *page_pool;
        struct stmmac_rx_buffer *buf_pool;
        struct stmmac_priv *priv_data;
@@ -95,6 +104,7 @@ struct stmmac_rx_queue {
        struct dma_desc *dma_rx ____cacheline_aligned_in_smp;
        unsigned int cur_rx;
        unsigned int dirty_rx;
+       unsigned int buf_alloc_num;
        u32 rx_zeroc_thresh;
        dma_addr_t dma_rx_phy;
        u32 rx_tail_addr;
@@ -109,6 +119,7 @@ struct stmmac_rx_queue {
 struct stmmac_channel {
        struct napi_struct rx_napi ____cacheline_aligned_in_smp;
        struct napi_struct tx_napi ____cacheline_aligned_in_smp;
+       struct napi_struct rxtx_napi ____cacheline_aligned_in_smp;
        struct stmmac_priv *priv_data;
        spinlock_t lock;
        u32 index;
@@ -239,6 +250,9 @@ struct stmmac_priv {
        int use_riwt;
        int irq_wake;
        spinlock_t ptp_lock;
+       /* Protects auxiliary snapshot registers from concurrent access. */
+       struct mutex aux_ts_lock;
+
        void __iomem *mmcaddr;
        void __iomem *ptpaddr;
        unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -283,6 +297,7 @@ struct stmmac_priv {
        struct stmmac_rss rss;
 
        /* XDP BPF Program */
+       unsigned long *af_xdp_zc_qps;
        struct bpf_prog *xdp_prog;
 };
 
@@ -328,6 +343,12 @@ static inline unsigned int stmmac_rx_offset(struct stmmac_priv *priv)
        return 0;
 }
 
+void stmmac_disable_rx_queue(struct stmmac_priv *priv, u32 queue);
+void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue);
+void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue);
+void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue);
+int stmmac_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags);
+
 #if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
 void stmmac_selftest_run(struct net_device *dev,
                         struct ethtool_test *etest, u64 *buf);
index 113c51b..074e2cd 100644 (file)
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/delay.h>
+#include <linux/ptp_clock_kernel.h>
 #include "common.h"
 #include "stmmac_ptp.h"
+#include "dwmac4.h"
+#include "stmmac.h"
 
 static void config_hw_tstamping(void __iomem *ioaddr, u32 data)
 {
@@ -163,6 +166,41 @@ static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
        *ptp_time = ns;
 }
 
+static void timestamp_interrupt(struct stmmac_priv *priv)
+{
+       u32 num_snapshot, ts_status, tsync_int;
+       struct ptp_clock_event event;
+       unsigned long flags;
+       u64 ptp_time;
+       int i;
+
+       tsync_int = readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE;
+
+       if (!tsync_int)
+               return;
+
+       /* Read timestamp status to clear interrupt from either external
+        * timestamp or start/end of PPS.
+        */
+       ts_status = readl(priv->ioaddr + GMAC_TIMESTAMP_STATUS);
+
+       if (!priv->plat->ext_snapshot_en)
+               return;
+
+       num_snapshot = (ts_status & GMAC_TIMESTAMP_ATSNS_MASK) >>
+                      GMAC_TIMESTAMP_ATSNS_SHIFT;
+
+       for (i = 0; i < num_snapshot; i++) {
+               spin_lock_irqsave(&priv->ptp_lock, flags);
+               get_ptptime(priv->ptpaddr, &ptp_time);
+               spin_unlock_irqrestore(&priv->ptp_lock, flags);
+               event.type = PTP_CLOCK_EXTTS;
+               event.index = 0;
+               event.timestamp = ptp_time;
+               ptp_clock_event(priv->ptp_clock, &event);
+       }
+}
+
 const struct stmmac_hwtimestamp stmmac_ptp = {
        .config_hw_tstamping = config_hw_tstamping,
        .init_systime = init_systime,
@@ -171,4 +209,5 @@ const struct stmmac_hwtimestamp stmmac_ptp = {
        .adjust_systime = adjust_systime,
        .get_systime = get_systime,
        .get_ptptime = get_ptptime,
+       .timestamp_interrupt = timestamp_interrupt,
 };
index 7728564..3a5ca58 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/udp.h>
 #include <linux/bpf_trace.h>
 #include <net/pkt_cls.h>
+#include <net/xdp_sock_drv.h>
 #include "stmmac_ptp.h"
 #include "stmmac.h"
 #include "stmmac_xdp.h"
@@ -69,6 +70,11 @@ MODULE_PARM_DESC(phyaddr, "Physical device address");
 #define STMMAC_TX_THRESH(x)    ((x)->dma_tx_size / 4)
 #define STMMAC_RX_THRESH(x)    ((x)->dma_rx_size / 4)
 
+/* Limit to make sure XDP TX and slow path can coexist */
+#define STMMAC_XSK_TX_BUDGET_MAX       256
+#define STMMAC_TX_XSK_AVAIL            16
+#define STMMAC_RX_FILL_BATCH           16
+
 #define STMMAC_XDP_PASS                0
 #define STMMAC_XDP_CONSUMED    BIT(0)
 #define STMMAC_XDP_TX          BIT(1)
@@ -117,6 +123,8 @@ static irqreturn_t stmmac_mac_interrupt(int irq, void *dev_id);
 static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id);
 static irqreturn_t stmmac_msi_intr_tx(int irq, void *data);
 static irqreturn_t stmmac_msi_intr_rx(int irq, void *data);
+static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue);
+static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue);
 
 #ifdef CONFIG_DEBUG_FS
 static const struct net_device_ops stmmac_netdev_ops;
@@ -179,11 +187,7 @@ static void stmmac_verify_args(void)
                eee_timer = STMMAC_DEFAULT_LPI_TIMER;
 }
 
-/**
- * stmmac_disable_all_queues - Disable all queues
- * @priv: driver private structure
- */
-static void stmmac_disable_all_queues(struct stmmac_priv *priv)
+static void __stmmac_disable_all_queues(struct stmmac_priv *priv)
 {
        u32 rx_queues_cnt = priv->plat->rx_queues_to_use;
        u32 tx_queues_cnt = priv->plat->tx_queues_to_use;
@@ -193,6 +197,12 @@ static void stmmac_disable_all_queues(struct stmmac_priv *priv)
        for (queue = 0; queue < maxq; queue++) {
                struct stmmac_channel *ch = &priv->channel[queue];
 
+               if (stmmac_xdp_is_enabled(priv) &&
+                   test_bit(queue, priv->af_xdp_zc_qps)) {
+                       napi_disable(&ch->rxtx_napi);
+                       continue;
+               }
+
                if (queue < rx_queues_cnt)
                        napi_disable(&ch->rx_napi);
                if (queue < tx_queues_cnt)
@@ -200,6 +210,28 @@ static void stmmac_disable_all_queues(struct stmmac_priv *priv)
        }
 }
 
+/**
+ * stmmac_disable_all_queues - Disable all queues
+ * @priv: driver private structure
+ */
+static void stmmac_disable_all_queues(struct stmmac_priv *priv)
+{
+       u32 rx_queues_cnt = priv->plat->rx_queues_to_use;
+       struct stmmac_rx_queue *rx_q;
+       u32 queue;
+
+       /* synchronize_rcu() needed for pending XDP buffers to drain */
+       for (queue = 0; queue < rx_queues_cnt; queue++) {
+               rx_q = &priv->rx_queue[queue];
+               if (rx_q->xsk_pool) {
+                       synchronize_rcu();
+                       break;
+               }
+       }
+
+       __stmmac_disable_all_queues(priv);
+}
+
 /**
  * stmmac_enable_all_queues - Enable all queues
  * @priv: driver private structure
@@ -214,6 +246,12 @@ static void stmmac_enable_all_queues(struct stmmac_priv *priv)
        for (queue = 0; queue < maxq; queue++) {
                struct stmmac_channel *ch = &priv->channel[queue];
 
+               if (stmmac_xdp_is_enabled(priv) &&
+                   test_bit(queue, priv->af_xdp_zc_qps)) {
+                       napi_enable(&ch->rxtx_napi);
+                       continue;
+               }
+
                if (queue < rx_queues_cnt)
                        napi_enable(&ch->rx_napi);
                if (queue < tx_queues_cnt)
@@ -1388,12 +1426,14 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
        struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
        struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
 
-       buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
-       if (!buf->page)
-               return -ENOMEM;
-       buf->page_offset = stmmac_rx_offset(priv);
+       if (!buf->page) {
+               buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
+               if (!buf->page)
+                       return -ENOMEM;
+               buf->page_offset = stmmac_rx_offset(priv);
+       }
 
-       if (priv->sph) {
+       if (priv->sph && !buf->sec_page) {
                buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
                if (!buf->sec_page)
                        return -ENOMEM;
@@ -1465,6 +1505,9 @@ static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i)
                tx_q->xdpf[i] = NULL;
        }
 
+       if (tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_XSK_TX)
+               tx_q->xsk_frames_done++;
+
        if (tx_q->tx_skbuff[i] &&
            tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_SKB) {
                dev_kfree_skb_any(tx_q->tx_skbuff[i]);
@@ -1475,6 +1518,120 @@ static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i)
        tx_q->tx_skbuff_dma[i].map_as_page = false;
 }
 
+/**
+ * dma_free_rx_skbufs - free RX dma buffers
+ * @priv: private structure
+ * @queue: RX queue index
+ */
+static void dma_free_rx_skbufs(struct stmmac_priv *priv, u32 queue)
+{
+       int i;
+
+       for (i = 0; i < priv->dma_rx_size; i++)
+               stmmac_free_rx_buffer(priv, queue, i);
+}
+
+static int stmmac_alloc_rx_buffers(struct stmmac_priv *priv, u32 queue,
+                                  gfp_t flags)
+{
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       int i;
+
+       for (i = 0; i < priv->dma_rx_size; i++) {
+               struct dma_desc *p;
+               int ret;
+
+               if (priv->extend_desc)
+                       p = &((rx_q->dma_erx + i)->basic);
+               else
+                       p = rx_q->dma_rx + i;
+
+               ret = stmmac_init_rx_buffers(priv, p, i, flags,
+                                            queue);
+               if (ret)
+                       return ret;
+
+               rx_q->buf_alloc_num++;
+       }
+
+       return 0;
+}
+
+/**
+ * dma_recycle_rx_skbufs - recycle RX dma buffers
+ * @priv: private structure
+ * @queue: RX queue index
+ */
+static void dma_recycle_rx_skbufs(struct stmmac_priv *priv, u32 queue)
+{
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       int i;
+
+       for (i = 0; i < priv->dma_rx_size; i++) {
+               struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
+
+               if (buf->page) {
+                       page_pool_recycle_direct(rx_q->page_pool, buf->page);
+                       buf->page = NULL;
+               }
+
+               if (priv->sph && buf->sec_page) {
+                       page_pool_recycle_direct(rx_q->page_pool, buf->sec_page);
+                       buf->sec_page = NULL;
+               }
+       }
+}
+
+/**
+ * dma_free_rx_xskbufs - free RX dma buffers from XSK pool
+ * @priv: private structure
+ * @queue: RX queue index
+ */
+static void dma_free_rx_xskbufs(struct stmmac_priv *priv, u32 queue)
+{
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       int i;
+
+       for (i = 0; i < priv->dma_rx_size; i++) {
+               struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
+
+               if (!buf->xdp)
+                       continue;
+
+               xsk_buff_free(buf->xdp);
+               buf->xdp = NULL;
+       }
+}
+
+static int stmmac_alloc_rx_buffers_zc(struct stmmac_priv *priv, u32 queue)
+{
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       int i;
+
+       for (i = 0; i < priv->dma_rx_size; i++) {
+               struct stmmac_rx_buffer *buf;
+               dma_addr_t dma_addr;
+               struct dma_desc *p;
+
+               if (priv->extend_desc)
+                       p = (struct dma_desc *)(rx_q->dma_erx + i);
+               else
+                       p = rx_q->dma_rx + i;
+
+               buf = &rx_q->buf_pool[i];
+
+               buf->xdp = xsk_buff_alloc(rx_q->xsk_pool);
+               if (!buf->xdp)
+                       return -ENOMEM;
+
+               dma_addr = xsk_buff_xdp_get_dma(buf->xdp);
+               stmmac_set_desc_addr(priv, p, dma_addr);
+               rx_q->buf_alloc_num++;
+       }
+
+       return 0;
+}
+
 /**
  * stmmac_reinit_rx_buffers - reinit the RX descriptor buffer.
  * @priv: driver private structure
@@ -1485,158 +1642,159 @@ static void stmmac_reinit_rx_buffers(struct stmmac_priv *priv)
 {
        u32 rx_count = priv->plat->rx_queues_to_use;
        u32 queue;
-       int i;
 
        for (queue = 0; queue < rx_count; queue++) {
                struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
 
-               for (i = 0; i < priv->dma_rx_size; i++) {
-                       struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
-
-                       if (buf->page) {
-                               page_pool_recycle_direct(rx_q->page_pool, buf->page);
-                               buf->page = NULL;
-                       }
+               if (rx_q->xsk_pool)
+                       dma_free_rx_xskbufs(priv, queue);
+               else
+                       dma_recycle_rx_skbufs(priv, queue);
 
-                       if (priv->sph && buf->sec_page) {
-                               page_pool_recycle_direct(rx_q->page_pool, buf->sec_page);
-                               buf->sec_page = NULL;
-                       }
-               }
+               rx_q->buf_alloc_num = 0;
        }
 
        for (queue = 0; queue < rx_count; queue++) {
                struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+               int ret;
 
-               for (i = 0; i < priv->dma_rx_size; i++) {
-                       struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
-                       struct dma_desc *p;
-
-                       if (priv->extend_desc)
-                               p = &((rx_q->dma_erx + i)->basic);
-                       else
-                               p = rx_q->dma_rx + i;
-
-                       if (!buf->page) {
-                               buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
-                               if (!buf->page)
-                                       goto err_reinit_rx_buffers;
-
-                               buf->addr = page_pool_get_dma_addr(buf->page) +
-                                           buf->page_offset;
-                       }
-
-                       if (priv->sph && !buf->sec_page) {
-                               buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
-                               if (!buf->sec_page)
-                                       goto err_reinit_rx_buffers;
-
-                               buf->sec_addr = page_pool_get_dma_addr(buf->sec_page);
-                       }
-
-                       stmmac_set_desc_addr(priv, p, buf->addr);
-                       if (priv->sph)
-                               stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, true);
-                       else
-                               stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, false);
-                       if (priv->dma_buf_sz == BUF_SIZE_16KiB)
-                               stmmac_init_desc3(priv, p);
+               if (rx_q->xsk_pool) {
+                       /* RX XDP ZC buffer pool may not be populated, e.g.
+                        * xdpsock TX-only.
+                        */
+                       stmmac_alloc_rx_buffers_zc(priv, queue);
+               } else {
+                       ret = stmmac_alloc_rx_buffers(priv, queue, GFP_KERNEL);
+                       if (ret < 0)
+                               goto err_reinit_rx_buffers;
                }
        }
 
        return;
 
 err_reinit_rx_buffers:
-       do {
-               while (--i >= 0)
-                       stmmac_free_rx_buffer(priv, queue, i);
+       while (queue >= 0) {
+               dma_free_rx_skbufs(priv, queue);
 
                if (queue == 0)
                        break;
 
-               i = priv->dma_rx_size;
-       } while (queue-- > 0);
+               queue--;
+       }
+}
+
+static struct xsk_buff_pool *stmmac_get_xsk_pool(struct stmmac_priv *priv, u32 queue)
+{
+       if (!stmmac_xdp_is_enabled(priv) || !test_bit(queue, priv->af_xdp_zc_qps))
+               return NULL;
+
+       return xsk_get_pool_from_qid(priv->dev, queue);
 }
 
 /**
- * init_dma_rx_desc_rings - init the RX descriptor rings
- * @dev: net device structure
+ * __init_dma_rx_desc_rings - init the RX descriptor ring (per queue)
+ * @priv: driver private structure
+ * @queue: RX queue index
  * @flags: gfp flag.
  * Description: this function initializes the DMA RX descriptors
  * and allocates the socket buffers. It supports the chained and ring
  * modes.
  */
-static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags)
+static int __init_dma_rx_desc_rings(struct stmmac_priv *priv, u32 queue, gfp_t flags)
 {
-       struct stmmac_priv *priv = netdev_priv(dev);
-       u32 rx_count = priv->plat->rx_queues_to_use;
-       int ret = -ENOMEM;
-       int queue;
-       int i;
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       int ret;
 
-       /* RX INITIALIZATION */
        netif_dbg(priv, probe, priv->dev,
-                 "SKB addresses:\nskb\t\tskb data\tdma data\n");
+                 "(%s) dma_rx_phy=0x%08x\n", __func__,
+                 (u32)rx_q->dma_rx_phy);
 
-       for (queue = 0; queue < rx_count; queue++) {
-               struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
-               int ret;
+       stmmac_clear_rx_descriptors(priv, queue);
 
-               netif_dbg(priv, probe, priv->dev,
-                         "(%s) dma_rx_phy=0x%08x\n", __func__,
-                         (u32)rx_q->dma_rx_phy);
+       xdp_rxq_info_unreg_mem_model(&rx_q->xdp_rxq);
 
-               stmmac_clear_rx_descriptors(priv, queue);
+       rx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue);
 
+       if (rx_q->xsk_pool) {
+               WARN_ON(xdp_rxq_info_reg_mem_model(&rx_q->xdp_rxq,
+                                                  MEM_TYPE_XSK_BUFF_POOL,
+                                                  NULL));
+               netdev_info(priv->dev,
+                           "Register MEM_TYPE_XSK_BUFF_POOL RxQ-%d\n",
+                           rx_q->queue_index);
+               xsk_pool_set_rxq_info(rx_q->xsk_pool, &rx_q->xdp_rxq);
+       } else {
                WARN_ON(xdp_rxq_info_reg_mem_model(&rx_q->xdp_rxq,
                                                   MEM_TYPE_PAGE_POOL,
                                                   rx_q->page_pool));
-
                netdev_info(priv->dev,
                            "Register MEM_TYPE_PAGE_POOL RxQ-%d\n",
                            rx_q->queue_index);
+       }
 
-               for (i = 0; i < priv->dma_rx_size; i++) {
-                       struct dma_desc *p;
+       if (rx_q->xsk_pool) {
+               /* RX XDP ZC buffer pool may not be populated, e.g.
+                * xdpsock TX-only.
+                */
+               stmmac_alloc_rx_buffers_zc(priv, queue);
+       } else {
+               ret = stmmac_alloc_rx_buffers(priv, queue, flags);
+               if (ret < 0)
+                       return -ENOMEM;
+       }
 
-                       if (priv->extend_desc)
-                               p = &((rx_q->dma_erx + i)->basic);
-                       else
-                               p = rx_q->dma_rx + i;
+       rx_q->cur_rx = 0;
+       rx_q->dirty_rx = 0;
 
-                       ret = stmmac_init_rx_buffers(priv, p, i, flags,
-                                                    queue);
-                       if (ret)
-                               goto err_init_rx_buffers;
-               }
+       /* Setup the chained descriptor addresses */
+       if (priv->mode == STMMAC_CHAIN_MODE) {
+               if (priv->extend_desc)
+                       stmmac_mode_init(priv, rx_q->dma_erx,
+                                        rx_q->dma_rx_phy,
+                                        priv->dma_rx_size, 1);
+               else
+                       stmmac_mode_init(priv, rx_q->dma_rx,
+                                        rx_q->dma_rx_phy,
+                                        priv->dma_rx_size, 0);
+       }
 
-               rx_q->cur_rx = 0;
-               rx_q->dirty_rx = (unsigned int)(i - priv->dma_rx_size);
-
-               /* Setup the chained descriptor addresses */
-               if (priv->mode == STMMAC_CHAIN_MODE) {
-                       if (priv->extend_desc)
-                               stmmac_mode_init(priv, rx_q->dma_erx,
-                                                rx_q->dma_rx_phy,
-                                                priv->dma_rx_size, 1);
-                       else
-                               stmmac_mode_init(priv, rx_q->dma_rx,
-                                                rx_q->dma_rx_phy,
-                                                priv->dma_rx_size, 0);
-               }
+       return 0;
+}
+
+static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       u32 rx_count = priv->plat->rx_queues_to_use;
+       u32 queue;
+       int ret;
+
+       /* RX INITIALIZATION */
+       netif_dbg(priv, probe, priv->dev,
+                 "SKB addresses:\nskb\t\tskb data\tdma data\n");
+
+       for (queue = 0; queue < rx_count; queue++) {
+               ret = __init_dma_rx_desc_rings(priv, queue, flags);
+               if (ret)
+                       goto err_init_rx_buffers;
        }
 
        return 0;
 
 err_init_rx_buffers:
        while (queue >= 0) {
-               while (--i >= 0)
-                       stmmac_free_rx_buffer(priv, queue, i);
+               struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+
+               if (rx_q->xsk_pool)
+                       dma_free_rx_xskbufs(priv, queue);
+               else
+                       dma_free_rx_skbufs(priv, queue);
+
+               rx_q->buf_alloc_num = 0;
+               rx_q->xsk_pool = NULL;
 
                if (queue == 0)
                        break;
 
-               i = priv->dma_rx_size;
                queue--;
        }
 
@@ -1644,63 +1802,75 @@ err_init_rx_buffers:
 }
 
 /**
- * init_dma_tx_desc_rings - init the TX descriptor rings
- * @dev: net device structure.
+ * __init_dma_tx_desc_rings - init the TX descriptor ring (per queue)
+ * @priv: driver private structure
+ * @queue : TX queue index
  * Description: this function initializes the DMA TX descriptors
  * and allocates the socket buffers. It supports the chained and ring
  * modes.
  */
-static int init_dma_tx_desc_rings(struct net_device *dev)
+static int __init_dma_tx_desc_rings(struct stmmac_priv *priv, u32 queue)
 {
-       struct stmmac_priv *priv = netdev_priv(dev);
-       u32 tx_queue_cnt = priv->plat->tx_queues_to_use;
-       u32 queue;
+       struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
        int i;
 
-       for (queue = 0; queue < tx_queue_cnt; queue++) {
-               struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
+       netif_dbg(priv, probe, priv->dev,
+                 "(%s) dma_tx_phy=0x%08x\n", __func__,
+                 (u32)tx_q->dma_tx_phy);
 
-               netif_dbg(priv, probe, priv->dev,
-                         "(%s) dma_tx_phy=0x%08x\n", __func__,
-                        (u32)tx_q->dma_tx_phy);
-
-               /* Setup the chained descriptor addresses */
-               if (priv->mode == STMMAC_CHAIN_MODE) {
-                       if (priv->extend_desc)
-                               stmmac_mode_init(priv, tx_q->dma_etx,
-                                                tx_q->dma_tx_phy,
-                                                priv->dma_tx_size, 1);
-                       else if (!(tx_q->tbs & STMMAC_TBS_AVAIL))
-                               stmmac_mode_init(priv, tx_q->dma_tx,
-                                                tx_q->dma_tx_phy,
-                                                priv->dma_tx_size, 0);
-               }
+       /* Setup the chained descriptor addresses */
+       if (priv->mode == STMMAC_CHAIN_MODE) {
+               if (priv->extend_desc)
+                       stmmac_mode_init(priv, tx_q->dma_etx,
+                                        tx_q->dma_tx_phy,
+                                        priv->dma_tx_size, 1);
+               else if (!(tx_q->tbs & STMMAC_TBS_AVAIL))
+                       stmmac_mode_init(priv, tx_q->dma_tx,
+                                        tx_q->dma_tx_phy,
+                                        priv->dma_tx_size, 0);
+       }
 
-               for (i = 0; i < priv->dma_tx_size; i++) {
-                       struct dma_desc *p;
-                       if (priv->extend_desc)
-                               p = &((tx_q->dma_etx + i)->basic);
-                       else if (tx_q->tbs & STMMAC_TBS_AVAIL)
-                               p = &((tx_q->dma_entx + i)->basic);
-                       else
-                               p = tx_q->dma_tx + i;
+       tx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue);
 
-                       stmmac_clear_desc(priv, p);
+       for (i = 0; i < priv->dma_tx_size; i++) {
+               struct dma_desc *p;
 
-                       tx_q->tx_skbuff_dma[i].buf = 0;
-                       tx_q->tx_skbuff_dma[i].map_as_page = false;
-                       tx_q->tx_skbuff_dma[i].len = 0;
-                       tx_q->tx_skbuff_dma[i].last_segment = false;
-                       tx_q->tx_skbuff[i] = NULL;
-               }
+               if (priv->extend_desc)
+                       p = &((tx_q->dma_etx + i)->basic);
+               else if (tx_q->tbs & STMMAC_TBS_AVAIL)
+                       p = &((tx_q->dma_entx + i)->basic);
+               else
+                       p = tx_q->dma_tx + i;
 
-               tx_q->dirty_tx = 0;
-               tx_q->cur_tx = 0;
-               tx_q->mss = 0;
+               stmmac_clear_desc(priv, p);
 
-               netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue));
+               tx_q->tx_skbuff_dma[i].buf = 0;
+               tx_q->tx_skbuff_dma[i].map_as_page = false;
+               tx_q->tx_skbuff_dma[i].len = 0;
+               tx_q->tx_skbuff_dma[i].last_segment = false;
+               tx_q->tx_skbuff[i] = NULL;
        }
 
+       tx_q->dirty_tx = 0;
+       tx_q->cur_tx = 0;
+       tx_q->mss = 0;
+
+       netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue));
+
+       return 0;
+}
+
+static int init_dma_tx_desc_rings(struct net_device *dev)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       u32 tx_queue_cnt;
+       u32 queue;
+
+       tx_queue_cnt = priv->plat->tx_queues_to_use;
+
+       for (queue = 0; queue < tx_queue_cnt; queue++)
+               __init_dma_tx_desc_rings(priv, queue);
+
        return 0;
 }
 
@@ -1731,19 +1901,6 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
        return ret;
 }
 
-/**
- * dma_free_rx_skbufs - free RX dma buffers
- * @priv: private structure
- * @queue: RX queue index
- */
-static void dma_free_rx_skbufs(struct stmmac_priv *priv, u32 queue)
-{
-       int i;
-
-       for (i = 0; i < priv->dma_rx_size; i++)
-               stmmac_free_rx_buffer(priv, queue, i);
-}
-
 /**
  * dma_free_tx_skbufs - free TX dma buffers
  * @priv: private structure
@@ -1751,10 +1908,19 @@ static void dma_free_rx_skbufs(struct stmmac_priv *priv, u32 queue)
  */
 static void dma_free_tx_skbufs(struct stmmac_priv *priv, u32 queue)
 {
+       struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
        int i;
 
+       tx_q->xsk_frames_done = 0;
+
        for (i = 0; i < priv->dma_tx_size; i++)
                stmmac_free_tx_buffer(priv, queue, i);
+
+       if (tx_q->xsk_pool && tx_q->xsk_frames_done) {
+               xsk_tx_completed(tx_q->xsk_pool, tx_q->xsk_frames_done);
+               tx_q->xsk_frames_done = 0;
+               tx_q->xsk_pool = NULL;
+       }
 }
 
 /**
@@ -1771,153 +1937,186 @@ static void stmmac_free_tx_skbufs(struct stmmac_priv *priv)
 }
 
 /**
- * free_dma_rx_desc_resources - free RX dma desc resources
+ * __free_dma_rx_desc_resources - free RX dma desc resources (per queue)
  * @priv: private structure
+ * @queue: RX queue index
  */
-static void free_dma_rx_desc_resources(struct stmmac_priv *priv)
+static void __free_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue)
 {
-       u32 rx_count = priv->plat->rx_queues_to_use;
-       u32 queue;
-
-       /* Free RX queue resources */
-       for (queue = 0; queue < rx_count; queue++) {
-               struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
 
-               /* Release the DMA RX socket buffers */
+       /* Release the DMA RX socket buffers */
+       if (rx_q->xsk_pool)
+               dma_free_rx_xskbufs(priv, queue);
+       else
                dma_free_rx_skbufs(priv, queue);
 
-               /* Free DMA regions of consistent memory previously allocated */
-               if (!priv->extend_desc)
-                       dma_free_coherent(priv->device, priv->dma_rx_size *
-                                         sizeof(struct dma_desc),
-                                         rx_q->dma_rx, rx_q->dma_rx_phy);
-               else
-                       dma_free_coherent(priv->device, priv->dma_rx_size *
-                                         sizeof(struct dma_extended_desc),
-                                         rx_q->dma_erx, rx_q->dma_rx_phy);
+       rx_q->buf_alloc_num = 0;
+       rx_q->xsk_pool = NULL;
 
-               if (xdp_rxq_info_is_reg(&rx_q->xdp_rxq))
-                       xdp_rxq_info_unreg(&rx_q->xdp_rxq);
+       /* Free DMA regions of consistent memory previously allocated */
+       if (!priv->extend_desc)
+               dma_free_coherent(priv->device, priv->dma_rx_size *
+                                 sizeof(struct dma_desc),
+                                 rx_q->dma_rx, rx_q->dma_rx_phy);
+       else
+               dma_free_coherent(priv->device, priv->dma_rx_size *
+                                 sizeof(struct dma_extended_desc),
+                                 rx_q->dma_erx, rx_q->dma_rx_phy);
 
-               kfree(rx_q->buf_pool);
-               if (rx_q->page_pool)
-                       page_pool_destroy(rx_q->page_pool);
-       }
+       if (xdp_rxq_info_is_reg(&rx_q->xdp_rxq))
+               xdp_rxq_info_unreg(&rx_q->xdp_rxq);
+
+       kfree(rx_q->buf_pool);
+       if (rx_q->page_pool)
+               page_pool_destroy(rx_q->page_pool);
+}
+
+static void free_dma_rx_desc_resources(struct stmmac_priv *priv)
+{
+       u32 rx_count = priv->plat->rx_queues_to_use;
+       u32 queue;
+
+       /* Free RX queue resources */
+       for (queue = 0; queue < rx_count; queue++)
+               __free_dma_rx_desc_resources(priv, queue);
 }
 
 /**
- * free_dma_tx_desc_resources - free TX dma desc resources
+ * __free_dma_tx_desc_resources - free TX dma desc resources (per queue)
  * @priv: private structure
+ * @queue: TX queue index
  */
-static void free_dma_tx_desc_resources(struct stmmac_priv *priv)
+static void __free_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue)
 {
-       u32 tx_count = priv->plat->tx_queues_to_use;
-       u32 queue;
+       struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
+       size_t size;
+       void *addr;
 
-       /* Free TX queue resources */
-       for (queue = 0; queue < tx_count; queue++) {
-               struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
-               size_t size;
-               void *addr;
+       /* Release the DMA TX socket buffers */
+       dma_free_tx_skbufs(priv, queue);
+
+       if (priv->extend_desc) {
+               size = sizeof(struct dma_extended_desc);
+               addr = tx_q->dma_etx;
+       } else if (tx_q->tbs & STMMAC_TBS_AVAIL) {
+               size = sizeof(struct dma_edesc);
+               addr = tx_q->dma_entx;
+       } else {
+               size = sizeof(struct dma_desc);
+               addr = tx_q->dma_tx;
+       }
 
-               /* Release the DMA TX socket buffers */
-               dma_free_tx_skbufs(priv, queue);
+       size *= priv->dma_tx_size;
 
-               if (priv->extend_desc) {
-                       size = sizeof(struct dma_extended_desc);
-                       addr = tx_q->dma_etx;
-               } else if (tx_q->tbs & STMMAC_TBS_AVAIL) {
-                       size = sizeof(struct dma_edesc);
-                       addr = tx_q->dma_entx;
-               } else {
-                       size = sizeof(struct dma_desc);
-                       addr = tx_q->dma_tx;
-               }
+       dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy);
 
-               size *= priv->dma_tx_size;
+       kfree(tx_q->tx_skbuff_dma);
+       kfree(tx_q->tx_skbuff);
+}
 
-               dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy);
+static void free_dma_tx_desc_resources(struct stmmac_priv *priv)
+{
+       u32 tx_count = priv->plat->tx_queues_to_use;
+       u32 queue;
 
-               kfree(tx_q->tx_skbuff_dma);
-               kfree(tx_q->tx_skbuff);
-       }
+       /* Free TX queue resources */
+       for (queue = 0; queue < tx_count; queue++)
+               __free_dma_tx_desc_resources(priv, queue);
 }
 
 /**
- * alloc_dma_rx_desc_resources - alloc RX resources.
+ * __alloc_dma_rx_desc_resources - alloc RX resources (per queue).
  * @priv: private structure
+ * @queue: RX queue index
  * Description: according to which descriptor can be used (extend or basic)
  * this function allocates the resources for TX and RX paths. In case of
  * reception, for example, it pre-allocated the RX socket buffer in order to
  * allow zero-copy mechanism.
  */
-static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv)
+static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue)
 {
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       struct stmmac_channel *ch = &priv->channel[queue];
        bool xdp_prog = stmmac_xdp_is_enabled(priv);
-       u32 rx_count = priv->plat->rx_queues_to_use;
-       int ret = -ENOMEM;
-       u32 queue;
+       struct page_pool_params pp_params = { 0 };
+       unsigned int num_pages;
+       unsigned int napi_id;
+       int ret;
 
-       /* RX queues buffers and DMA */
-       for (queue = 0; queue < rx_count; queue++) {
-               struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
-               struct stmmac_channel *ch = &priv->channel[queue];
-               struct page_pool_params pp_params = { 0 };
-               unsigned int num_pages;
-               int ret;
+       rx_q->queue_index = queue;
+       rx_q->priv_data = priv;
+
+       pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
+       pp_params.pool_size = priv->dma_rx_size;
+       num_pages = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE);
+       pp_params.order = ilog2(num_pages);
+       pp_params.nid = dev_to_node(priv->device);
+       pp_params.dev = priv->device;
+       pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
+       pp_params.offset = stmmac_rx_offset(priv);
+       pp_params.max_len = STMMAC_MAX_RX_BUF_SIZE(num_pages);
+
+       rx_q->page_pool = page_pool_create(&pp_params);
+       if (IS_ERR(rx_q->page_pool)) {
+               ret = PTR_ERR(rx_q->page_pool);
+               rx_q->page_pool = NULL;
+               return ret;
+       }
 
-               rx_q->queue_index = queue;
-               rx_q->priv_data = priv;
-
-               pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
-               pp_params.pool_size = priv->dma_rx_size;
-               num_pages = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE);
-               pp_params.order = ilog2(num_pages);
-               pp_params.nid = dev_to_node(priv->device);
-               pp_params.dev = priv->device;
-               pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
-               pp_params.offset = stmmac_rx_offset(priv);
-               pp_params.max_len = STMMAC_MAX_RX_BUF_SIZE(num_pages);
-
-               rx_q->page_pool = page_pool_create(&pp_params);
-               if (IS_ERR(rx_q->page_pool)) {
-                       ret = PTR_ERR(rx_q->page_pool);
-                       rx_q->page_pool = NULL;
-                       goto err_dma;
-               }
+       rx_q->buf_pool = kcalloc(priv->dma_rx_size,
+                                sizeof(*rx_q->buf_pool),
+                                GFP_KERNEL);
+       if (!rx_q->buf_pool)
+               return -ENOMEM;
 
-               rx_q->buf_pool = kcalloc(priv->dma_rx_size,
-                                        sizeof(*rx_q->buf_pool),
-                                        GFP_KERNEL);
-               if (!rx_q->buf_pool)
-                       goto err_dma;
+       if (priv->extend_desc) {
+               rx_q->dma_erx = dma_alloc_coherent(priv->device,
+                                                  priv->dma_rx_size *
+                                                  sizeof(struct dma_extended_desc),
+                                                  &rx_q->dma_rx_phy,
+                                                  GFP_KERNEL);
+               if (!rx_q->dma_erx)
+                       return -ENOMEM;
 
-               if (priv->extend_desc) {
-                       rx_q->dma_erx = dma_alloc_coherent(priv->device,
-                                                          priv->dma_rx_size *
-                                                          sizeof(struct dma_extended_desc),
-                                                          &rx_q->dma_rx_phy,
-                                                          GFP_KERNEL);
-                       if (!rx_q->dma_erx)
-                               goto err_dma;
+       } else {
+               rx_q->dma_rx = dma_alloc_coherent(priv->device,
+                                                 priv->dma_rx_size *
+                                                 sizeof(struct dma_desc),
+                                                 &rx_q->dma_rx_phy,
+                                                 GFP_KERNEL);
+               if (!rx_q->dma_rx)
+                       return -ENOMEM;
+       }
 
-               } else {
-                       rx_q->dma_rx = dma_alloc_coherent(priv->device,
-                                                         priv->dma_rx_size *
-                                                         sizeof(struct dma_desc),
-                                                         &rx_q->dma_rx_phy,
-                                                         GFP_KERNEL);
-                       if (!rx_q->dma_rx)
-                               goto err_dma;
-               }
+       if (stmmac_xdp_is_enabled(priv) &&
+           test_bit(queue, priv->af_xdp_zc_qps))
+               napi_id = ch->rxtx_napi.napi_id;
+       else
+               napi_id = ch->rx_napi.napi_id;
 
-               ret = xdp_rxq_info_reg(&rx_q->xdp_rxq, priv->dev,
-                                      rx_q->queue_index,
-                                      ch->rx_napi.napi_id);
-               if (ret) {
-                       netdev_err(priv->dev, "Failed to register xdp rxq info\n");
+       ret = xdp_rxq_info_reg(&rx_q->xdp_rxq, priv->dev,
+                              rx_q->queue_index,
+                              napi_id);
+       if (ret) {
+               netdev_err(priv->dev, "Failed to register xdp rxq info\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv)
+{
+       u32 rx_count = priv->plat->rx_queues_to_use;
+       u32 queue;
+       int ret;
+
+       /* RX queues buffers and DMA */
+       for (queue = 0; queue < rx_count; queue++) {
+               ret = __alloc_dma_rx_desc_resources(priv, queue);
+               if (ret)
                        goto err_dma;
-               }
        }
 
        return 0;
@@ -1929,60 +2128,70 @@ err_dma:
 }
 
 /**
- * alloc_dma_tx_desc_resources - alloc TX resources.
+ * __alloc_dma_tx_desc_resources - alloc TX resources (per queue).
  * @priv: private structure
+ * @queue: TX queue index
  * Description: according to which descriptor can be used (extend or basic)
  * this function allocates the resources for TX and RX paths. In case of
  * reception, for example, it pre-allocated the RX socket buffer in order to
  * allow zero-copy mechanism.
  */
-static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv)
+static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue)
 {
-       u32 tx_count = priv->plat->tx_queues_to_use;
-       int ret = -ENOMEM;
-       u32 queue;
+       struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
+       size_t size;
+       void *addr;
 
-       /* TX queues buffers and DMA */
-       for (queue = 0; queue < tx_count; queue++) {
-               struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
-               size_t size;
-               void *addr;
+       tx_q->queue_index = queue;
+       tx_q->priv_data = priv;
 
-               tx_q->queue_index = queue;
-               tx_q->priv_data = priv;
+       tx_q->tx_skbuff_dma = kcalloc(priv->dma_tx_size,
+                                     sizeof(*tx_q->tx_skbuff_dma),
+                                     GFP_KERNEL);
+       if (!tx_q->tx_skbuff_dma)
+               return -ENOMEM;
 
-               tx_q->tx_skbuff_dma = kcalloc(priv->dma_tx_size,
-                                             sizeof(*tx_q->tx_skbuff_dma),
-                                             GFP_KERNEL);
-               if (!tx_q->tx_skbuff_dma)
-                       goto err_dma;
+       tx_q->tx_skbuff = kcalloc(priv->dma_tx_size,
+                                 sizeof(struct sk_buff *),
+                                 GFP_KERNEL);
+       if (!tx_q->tx_skbuff)
+               return -ENOMEM;
 
-               tx_q->tx_skbuff = kcalloc(priv->dma_tx_size,
-                                         sizeof(struct sk_buff *),
-                                         GFP_KERNEL);
-               if (!tx_q->tx_skbuff)
-                       goto err_dma;
+       if (priv->extend_desc)
+               size = sizeof(struct dma_extended_desc);
+       else if (tx_q->tbs & STMMAC_TBS_AVAIL)
+               size = sizeof(struct dma_edesc);
+       else
+               size = sizeof(struct dma_desc);
 
-               if (priv->extend_desc)
-                       size = sizeof(struct dma_extended_desc);
-               else if (tx_q->tbs & STMMAC_TBS_AVAIL)
-                       size = sizeof(struct dma_edesc);
-               else
-                       size = sizeof(struct dma_desc);
+       size *= priv->dma_tx_size;
 
-               size *= priv->dma_tx_size;
+       addr = dma_alloc_coherent(priv->device, size,
+                                 &tx_q->dma_tx_phy, GFP_KERNEL);
+       if (!addr)
+               return -ENOMEM;
 
-               addr = dma_alloc_coherent(priv->device, size,
-                                         &tx_q->dma_tx_phy, GFP_KERNEL);
-               if (!addr)
-                       goto err_dma;
+       if (priv->extend_desc)
+               tx_q->dma_etx = addr;
+       else if (tx_q->tbs & STMMAC_TBS_AVAIL)
+               tx_q->dma_entx = addr;
+       else
+               tx_q->dma_tx = addr;
 
-               if (priv->extend_desc)
-                       tx_q->dma_etx = addr;
-               else if (tx_q->tbs & STMMAC_TBS_AVAIL)
-                       tx_q->dma_entx = addr;
-               else
-                       tx_q->dma_tx = addr;
+       return 0;
+}
+
+static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv)
+{
+       u32 tx_count = priv->plat->tx_queues_to_use;
+       u32 queue;
+       int ret;
+
+       /* TX queues buffers and DMA */
+       for (queue = 0; queue < tx_count; queue++) {
+               ret = __alloc_dma_tx_desc_resources(priv, queue);
+               if (ret)
+                       goto err_dma;
        }
 
        return 0;
@@ -2180,22 +2389,129 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
                rxmode = SF_DMA_MODE;
        }
 
-       /* configure all channels */
-       for (chan = 0; chan < rx_channels_count; chan++) {
-               qmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
+       /* configure all channels */
+       for (chan = 0; chan < rx_channels_count; chan++) {
+               struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan];
+               u32 buf_size;
+
+               qmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
+
+               stmmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan,
+                               rxfifosz, qmode);
+
+               if (rx_q->xsk_pool) {
+                       buf_size = xsk_pool_get_rx_frame_size(rx_q->xsk_pool);
+                       stmmac_set_dma_bfsize(priv, priv->ioaddr,
+                                             buf_size,
+                                             chan);
+               } else {
+                       stmmac_set_dma_bfsize(priv, priv->ioaddr,
+                                             priv->dma_buf_sz,
+                                             chan);
+               }
+       }
+
+       for (chan = 0; chan < tx_channels_count; chan++) {
+               qmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
+
+               stmmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan,
+                               txfifosz, qmode);
+       }
+}
+
+static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
+{
+       struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue);
+       struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
+       struct xsk_buff_pool *pool = tx_q->xsk_pool;
+       unsigned int entry = tx_q->cur_tx;
+       struct dma_desc *tx_desc = NULL;
+       struct xdp_desc xdp_desc;
+       bool work_done = true;
+
+       /* Avoids TX time-out as we are sharing with slow path */
+       nq->trans_start = jiffies;
+
+       budget = min(budget, stmmac_tx_avail(priv, queue));
+
+       while (budget-- > 0) {
+               dma_addr_t dma_addr;
+               bool set_ic;
+
+               /* We are sharing with slow path and stop XSK TX desc submission when
+                * available TX ring is less than threshold.
+                */
+               if (unlikely(stmmac_tx_avail(priv, queue) < STMMAC_TX_XSK_AVAIL) ||
+                   !netif_carrier_ok(priv->dev)) {
+                       work_done = false;
+                       break;
+               }
+
+               if (!xsk_tx_peek_desc(pool, &xdp_desc))
+                       break;
+
+               if (likely(priv->extend_desc))
+                       tx_desc = (struct dma_desc *)(tx_q->dma_etx + entry);
+               else if (tx_q->tbs & STMMAC_TBS_AVAIL)
+                       tx_desc = &tx_q->dma_entx[entry].basic;
+               else
+                       tx_desc = tx_q->dma_tx + entry;
+
+               dma_addr = xsk_buff_raw_get_dma(pool, xdp_desc.addr);
+               xsk_buff_raw_dma_sync_for_device(pool, dma_addr, xdp_desc.len);
 
-               stmmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan,
-                               rxfifosz, qmode);
-               stmmac_set_dma_bfsize(priv, priv->ioaddr, priv->dma_buf_sz,
-                               chan);
-       }
+               tx_q->tx_skbuff_dma[entry].buf_type = STMMAC_TXBUF_T_XSK_TX;
 
-       for (chan = 0; chan < tx_channels_count; chan++) {
-               qmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
+               /* To return XDP buffer to XSK pool, we simple call
+                * xsk_tx_completed(), so we don't need to fill up
+                * 'buf' and 'xdpf'.
+                */
+               tx_q->tx_skbuff_dma[entry].buf = 0;
+               tx_q->xdpf[entry] = NULL;
 
-               stmmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan,
-                               txfifosz, qmode);
+               tx_q->tx_skbuff_dma[entry].map_as_page = false;
+               tx_q->tx_skbuff_dma[entry].len = xdp_desc.len;
+               tx_q->tx_skbuff_dma[entry].last_segment = true;
+               tx_q->tx_skbuff_dma[entry].is_jumbo = false;
+
+               stmmac_set_desc_addr(priv, tx_desc, dma_addr);
+
+               tx_q->tx_count_frames++;
+
+               if (!priv->tx_coal_frames[queue])
+                       set_ic = false;
+               else if (tx_q->tx_count_frames % priv->tx_coal_frames[queue] == 0)
+                       set_ic = true;
+               else
+                       set_ic = false;
+
+               if (set_ic) {
+                       tx_q->tx_count_frames = 0;
+                       stmmac_set_tx_ic(priv, tx_desc);
+                       priv->xstats.tx_set_ic_bit++;
+               }
+
+               stmmac_prepare_tx_desc(priv, tx_desc, 1, xdp_desc.len,
+                                      true, priv->mode, true, true,
+                                      xdp_desc.len);
+
+               stmmac_enable_dma_transmission(priv, priv->ioaddr);
+
+               tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_tx_size);
+               entry = tx_q->cur_tx;
+       }
+
+       if (tx_desc) {
+               stmmac_flush_tx_descriptors(priv, queue);
+               xsk_tx_release(pool);
        }
+
+       /* Return true if all of the 3 conditions are met
+        *  a) TX Budget is still available
+        *  b) work_done = true when XSK TX desc peek is empty (no more
+        *     pending XSK TX for transmission)
+        */
+       return !!budget && work_done;
 }
 
 /**
@@ -2209,14 +2525,18 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
 {
        struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
        unsigned int bytes_compl = 0, pkts_compl = 0;
-       unsigned int entry, count = 0;
+       unsigned int entry, xmits = 0, count = 0;
 
        __netif_tx_lock_bh(netdev_get_tx_queue(priv->dev, queue));
 
        priv->xstats.tx_clean++;
 
+       tx_q->xsk_frames_done = 0;
+
        entry = tx_q->dirty_tx;
-       while ((entry != tx_q->cur_tx) && (count < budget)) {
+
+       /* Try to clean all TX complete frame in 1 shot */
+       while ((entry != tx_q->cur_tx) && count < priv->dma_tx_size) {
                struct xdp_frame *xdpf;
                struct sk_buff *skb;
                struct dma_desc *p;
@@ -2301,6 +2621,9 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
                        tx_q->xdpf[entry] = NULL;
                }
 
+               if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_XSK_TX)
+                       tx_q->xsk_frames_done++;
+
                if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_SKB) {
                        if (likely(skb)) {
                                pkts_compl++;
@@ -2328,6 +2651,28 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
                netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, queue));
        }
 
+       if (tx_q->xsk_pool) {
+               bool work_done;
+
+               if (tx_q->xsk_frames_done)
+                       xsk_tx_completed(tx_q->xsk_pool, tx_q->xsk_frames_done);
+
+               if (xsk_uses_need_wakeup(tx_q->xsk_pool))
+                       xsk_set_tx_need_wakeup(tx_q->xsk_pool);
+
+               /* For XSK TX, we try to send as many as possible.
+                * If XSK work done (XSK TX desc empty and budget still
+                * available), return "budget - 1" to reenable TX IRQ.
+                * Else, return "budget" to make NAPI continue polling.
+                */
+               work_done = stmmac_xdp_xmit_zc(priv, queue,
+                                              STMMAC_XSK_TX_BUDGET_MAX);
+               if (work_done)
+                       xmits = budget - 1;
+               else
+                       xmits = budget;
+       }
+
        if (priv->eee_enabled && !priv->tx_path_in_lpi_mode &&
            priv->eee_sw_timer_en) {
                stmmac_enable_eee_mode(priv);
@@ -2342,7 +2687,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
 
        __netif_tx_unlock_bh(netdev_get_tx_queue(priv->dev, queue));
 
-       return count;
+       /* Combine decisions from TX clean and XSK TX */
+       return max(count, xmits);
 }
 
 /**
@@ -2424,24 +2770,31 @@ static int stmmac_napi_check(struct stmmac_priv *priv, u32 chan, u32 dir)
 {
        int status = stmmac_dma_interrupt_status(priv, priv->ioaddr,
                                                 &priv->xstats, chan, dir);
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan];
+       struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan];
        struct stmmac_channel *ch = &priv->channel[chan];
+       struct napi_struct *rx_napi;
+       struct napi_struct *tx_napi;
        unsigned long flags;
 
+       rx_napi = rx_q->xsk_pool ? &ch->rxtx_napi : &ch->rx_napi;
+       tx_napi = tx_q->xsk_pool ? &ch->rxtx_napi : &ch->tx_napi;
+
        if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use)) {
-               if (napi_schedule_prep(&ch->rx_napi)) {
+               if (napi_schedule_prep(rx_napi)) {
                        spin_lock_irqsave(&ch->lock, flags);
                        stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 0);
                        spin_unlock_irqrestore(&ch->lock, flags);
-                       __napi_schedule(&ch->rx_napi);
+                       __napi_schedule(rx_napi);
                }
        }
 
        if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use)) {
-               if (napi_schedule_prep(&ch->tx_napi)) {
+               if (napi_schedule_prep(tx_napi)) {
                        spin_lock_irqsave(&ch->lock, flags);
                        stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 0, 1);
                        spin_unlock_irqrestore(&ch->lock, flags);
-                       __napi_schedule(&ch->tx_napi);
+                       __napi_schedule(tx_napi);
                }
        }
 
@@ -2598,7 +2951,7 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
                                    rx_q->dma_rx_phy, chan);
 
                rx_q->rx_tail_addr = rx_q->dma_rx_phy +
-                                    (priv->dma_rx_size *
+                                    (rx_q->buf_alloc_num *
                                      sizeof(struct dma_desc));
                stmmac_set_rx_tail_ptr(priv, priv->ioaddr,
                                       rx_q->rx_tail_addr, chan);
@@ -2639,16 +2992,18 @@ static enum hrtimer_restart stmmac_tx_timer(struct hrtimer *t)
        struct stmmac_tx_queue *tx_q = container_of(t, struct stmmac_tx_queue, txtimer);
        struct stmmac_priv *priv = tx_q->priv_data;
        struct stmmac_channel *ch;
+       struct napi_struct *napi;
 
        ch = &priv->channel[tx_q->queue_index];
+       napi = tx_q->xsk_pool ? &ch->rxtx_napi : &ch->tx_napi;
 
-       if (likely(napi_schedule_prep(&ch->tx_napi))) {
+       if (likely(napi_schedule_prep(napi))) {
                unsigned long flags;
 
                spin_lock_irqsave(&ch->lock, flags);
                stmmac_disable_dma_irq(priv, priv->ioaddr, ch->index, 0, 1);
                spin_unlock_irqrestore(&ch->lock, flags);
-               __napi_schedule(&ch->tx_napi);
+               __napi_schedule(napi);
        }
 
        return HRTIMER_NORESTART;
@@ -4318,114 +4673,421 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
                priv->xstats.tx_set_ic_bit++;
        }
 
-       stmmac_enable_dma_transmission(priv, priv->ioaddr);
+       stmmac_enable_dma_transmission(priv, priv->ioaddr);
+
+       entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size);
+       tx_q->cur_tx = entry;
+
+       return STMMAC_XDP_TX;
+}
+
+static int stmmac_xdp_get_tx_queue(struct stmmac_priv *priv,
+                                  int cpu)
+{
+       int index = cpu;
+
+       if (unlikely(index < 0))
+               index = 0;
+
+       while (index >= priv->plat->tx_queues_to_use)
+               index -= priv->plat->tx_queues_to_use;
+
+       return index;
+}
+
+static int stmmac_xdp_xmit_back(struct stmmac_priv *priv,
+                               struct xdp_buff *xdp)
+{
+       struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
+       int cpu = smp_processor_id();
+       struct netdev_queue *nq;
+       int queue;
+       int res;
+
+       if (unlikely(!xdpf))
+               return STMMAC_XDP_CONSUMED;
+
+       queue = stmmac_xdp_get_tx_queue(priv, cpu);
+       nq = netdev_get_tx_queue(priv->dev, queue);
+
+       __netif_tx_lock(nq, cpu);
+       /* Avoids TX time-out as we are sharing with slow path */
+       nq->trans_start = jiffies;
+
+       res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false);
+       if (res == STMMAC_XDP_TX)
+               stmmac_flush_tx_descriptors(priv, queue);
+
+       __netif_tx_unlock(nq);
+
+       return res;
+}
+
+/* This function assumes rcu_read_lock() is held by the caller. */
+static int __stmmac_xdp_run_prog(struct stmmac_priv *priv,
+                                struct bpf_prog *prog,
+                                struct xdp_buff *xdp)
+{
+       u32 act;
+       int res;
+
+       act = bpf_prog_run_xdp(prog, xdp);
+       switch (act) {
+       case XDP_PASS:
+               res = STMMAC_XDP_PASS;
+               break;
+       case XDP_TX:
+               res = stmmac_xdp_xmit_back(priv, xdp);
+               break;
+       case XDP_REDIRECT:
+               if (xdp_do_redirect(priv->dev, xdp, prog) < 0)
+                       res = STMMAC_XDP_CONSUMED;
+               else
+                       res = STMMAC_XDP_REDIRECT;
+               break;
+       default:
+               bpf_warn_invalid_xdp_action(act);
+               fallthrough;
+       case XDP_ABORTED:
+               trace_xdp_exception(priv->dev, prog, act);
+               fallthrough;
+       case XDP_DROP:
+               res = STMMAC_XDP_CONSUMED;
+               break;
+       }
+
+       return res;
+}
+
+static struct sk_buff *stmmac_xdp_run_prog(struct stmmac_priv *priv,
+                                          struct xdp_buff *xdp)
+{
+       struct bpf_prog *prog;
+       int res;
+
+       rcu_read_lock();
+
+       prog = READ_ONCE(priv->xdp_prog);
+       if (!prog) {
+               res = STMMAC_XDP_PASS;
+               goto unlock;
+       }
+
+       res = __stmmac_xdp_run_prog(priv, prog, xdp);
+unlock:
+       rcu_read_unlock();
+       return ERR_PTR(-res);
+}
+
+static void stmmac_finalize_xdp_rx(struct stmmac_priv *priv,
+                                  int xdp_status)
+{
+       int cpu = smp_processor_id();
+       int queue;
+
+       queue = stmmac_xdp_get_tx_queue(priv, cpu);
+
+       if (xdp_status & STMMAC_XDP_TX)
+               stmmac_tx_timer_arm(priv, queue);
+
+       if (xdp_status & STMMAC_XDP_REDIRECT)
+               xdp_do_flush();
+}
+
+static struct sk_buff *stmmac_construct_skb_zc(struct stmmac_channel *ch,
+                                              struct xdp_buff *xdp)
+{
+       unsigned int metasize = xdp->data - xdp->data_meta;
+       unsigned int datasize = xdp->data_end - xdp->data;
+       struct sk_buff *skb;
+
+       skb = __napi_alloc_skb(&ch->rxtx_napi,
+                              xdp->data_end - xdp->data_hard_start,
+                              GFP_ATOMIC | __GFP_NOWARN);
+       if (unlikely(!skb))
+               return NULL;
+
+       skb_reserve(skb, xdp->data - xdp->data_hard_start);
+       memcpy(__skb_put(skb, datasize), xdp->data, datasize);
+       if (metasize)
+               skb_metadata_set(skb, metasize);
+
+       return skb;
+}
+
+static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
+                                  struct dma_desc *p, struct dma_desc *np,
+                                  struct xdp_buff *xdp)
+{
+       struct stmmac_channel *ch = &priv->channel[queue];
+       unsigned int len = xdp->data_end - xdp->data;
+       enum pkt_hash_types hash_type;
+       int coe = priv->hw->rx_csum;
+       struct sk_buff *skb;
+       u32 hash;
+
+       skb = stmmac_construct_skb_zc(ch, xdp);
+       if (!skb) {
+               priv->dev->stats.rx_dropped++;
+               return;
+       }
+
+       stmmac_get_rx_hwtstamp(priv, p, np, skb);
+       stmmac_rx_vlan(priv->dev, skb);
+       skb->protocol = eth_type_trans(skb, priv->dev);
+
+       if (unlikely(!coe))
+               skb_checksum_none_assert(skb);
+       else
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       if (!stmmac_get_rx_hash(priv, p, &hash, &hash_type))
+               skb_set_hash(skb, hash, hash_type);
+
+       skb_record_rx_queue(skb, queue);
+       napi_gro_receive(&ch->rxtx_napi, skb);
+
+       priv->dev->stats.rx_packets++;
+       priv->dev->stats.rx_bytes += len;
+}
+
+static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
+{
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       unsigned int entry = rx_q->dirty_rx;
+       struct dma_desc *rx_desc = NULL;
+       bool ret = true;
+
+       budget = min(budget, stmmac_rx_dirty(priv, queue));
+
+       while (budget-- > 0 && entry != rx_q->cur_rx) {
+               struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry];
+               dma_addr_t dma_addr;
+               bool use_rx_wd;
+
+               if (!buf->xdp) {
+                       buf->xdp = xsk_buff_alloc(rx_q->xsk_pool);
+                       if (!buf->xdp) {
+                               ret = false;
+                               break;
+                       }
+               }
+
+               if (priv->extend_desc)
+                       rx_desc = (struct dma_desc *)(rx_q->dma_erx + entry);
+               else
+                       rx_desc = rx_q->dma_rx + entry;
+
+               dma_addr = xsk_buff_xdp_get_dma(buf->xdp);
+               stmmac_set_desc_addr(priv, rx_desc, dma_addr);
+               stmmac_set_desc_sec_addr(priv, rx_desc, 0, false);
+               stmmac_refill_desc3(priv, rx_q, rx_desc);
+
+               rx_q->rx_count_frames++;
+               rx_q->rx_count_frames += priv->rx_coal_frames[queue];
+               if (rx_q->rx_count_frames > priv->rx_coal_frames[queue])
+                       rx_q->rx_count_frames = 0;
+
+               use_rx_wd = !priv->rx_coal_frames[queue];
+               use_rx_wd |= rx_q->rx_count_frames > 0;
+               if (!priv->use_riwt)
+                       use_rx_wd = false;
+
+               dma_wmb();
+               stmmac_set_rx_owner(priv, rx_desc, use_rx_wd);
+
+               entry = STMMAC_GET_ENTRY(entry, priv->dma_rx_size);
+       }
+
+       if (rx_desc) {
+               rx_q->dirty_rx = entry;
+               rx_q->rx_tail_addr = rx_q->dma_rx_phy +
+                                    (rx_q->dirty_rx * sizeof(struct dma_desc));
+               stmmac_set_rx_tail_ptr(priv, priv->ioaddr, rx_q->rx_tail_addr, queue);
+       }
+
+       return ret;
+}
+
+static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
+{
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       unsigned int count = 0, error = 0, len = 0;
+       int dirty = stmmac_rx_dirty(priv, queue);
+       unsigned int next_entry = rx_q->cur_rx;
+       unsigned int desc_size;
+       struct bpf_prog *prog;
+       bool failure = false;
+       int xdp_status = 0;
+       int status = 0;
+
+       if (netif_msg_rx_status(priv)) {
+               void *rx_head;
+
+               netdev_dbg(priv->dev, "%s: descriptor ring:\n", __func__);
+               if (priv->extend_desc) {
+                       rx_head = (void *)rx_q->dma_erx;
+                       desc_size = sizeof(struct dma_extended_desc);
+               } else {
+                       rx_head = (void *)rx_q->dma_rx;
+                       desc_size = sizeof(struct dma_desc);
+               }
+
+               stmmac_display_ring(priv, rx_head, priv->dma_rx_size, true,
+                                   rx_q->dma_rx_phy, desc_size);
+       }
+       while (count < limit) {
+               struct stmmac_rx_buffer *buf;
+               unsigned int buf1_len = 0;
+               struct dma_desc *np, *p;
+               int entry;
+               int res;
+
+               if (!count && rx_q->state_saved) {
+                       error = rx_q->state.error;
+                       len = rx_q->state.len;
+               } else {
+                       rx_q->state_saved = false;
+                       error = 0;
+                       len = 0;
+               }
+
+               if (count >= limit)
+                       break;
+
+read_again:
+               buf1_len = 0;
+               entry = next_entry;
+               buf = &rx_q->buf_pool[entry];
 
-       entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size);
-       tx_q->cur_tx = entry;
+               if (dirty >= STMMAC_RX_FILL_BATCH) {
+                       failure = failure ||
+                                 !stmmac_rx_refill_zc(priv, queue, dirty);
+                       dirty = 0;
+               }
 
-       return STMMAC_XDP_TX;
-}
+               if (priv->extend_desc)
+                       p = (struct dma_desc *)(rx_q->dma_erx + entry);
+               else
+                       p = rx_q->dma_rx + entry;
 
-static int stmmac_xdp_get_tx_queue(struct stmmac_priv *priv,
-                                  int cpu)
-{
-       int index = cpu;
+               /* read the status of the incoming frame */
+               status = stmmac_rx_status(priv, &priv->dev->stats,
+                                         &priv->xstats, p);
+               /* check if managed by the DMA otherwise go ahead */
+               if (unlikely(status & dma_own))
+                       break;
 
-       if (unlikely(index < 0))
-               index = 0;
+               /* Prefetch the next RX descriptor */
+               rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx,
+                                               priv->dma_rx_size);
+               next_entry = rx_q->cur_rx;
 
-       while (index >= priv->plat->tx_queues_to_use)
-               index -= priv->plat->tx_queues_to_use;
+               if (priv->extend_desc)
+                       np = (struct dma_desc *)(rx_q->dma_erx + next_entry);
+               else
+                       np = rx_q->dma_rx + next_entry;
 
-       return index;
-}
+               prefetch(np);
 
-static int stmmac_xdp_xmit_back(struct stmmac_priv *priv,
-                               struct xdp_buff *xdp)
-{
-       struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
-       int cpu = smp_processor_id();
-       struct netdev_queue *nq;
-       int queue;
-       int res;
+               if (priv->extend_desc)
+                       stmmac_rx_extended_status(priv, &priv->dev->stats,
+                                                 &priv->xstats,
+                                                 rx_q->dma_erx + entry);
+               if (unlikely(status == discard_frame)) {
+                       xsk_buff_free(buf->xdp);
+                       buf->xdp = NULL;
+                       dirty++;
+                       error = 1;
+                       if (!priv->hwts_rx_en)
+                               priv->dev->stats.rx_errors++;
+               }
 
-       if (unlikely(!xdpf))
-               return STMMAC_XDP_CONSUMED;
+               if (unlikely(error && (status & rx_not_ls)))
+                       goto read_again;
+               if (unlikely(error)) {
+                       count++;
+                       continue;
+               }
 
-       queue = stmmac_xdp_get_tx_queue(priv, cpu);
-       nq = netdev_get_tx_queue(priv->dev, queue);
+               /* Ensure a valid XSK buffer before proceed */
+               if (!buf->xdp)
+                       break;
 
-       __netif_tx_lock(nq, cpu);
-       /* Avoids TX time-out as we are sharing with slow path */
-       nq->trans_start = jiffies;
+               /* XSK pool expects RX frame 1:1 mapped to XSK buffer */
+               if (likely(status & rx_not_ls)) {
+                       xsk_buff_free(buf->xdp);
+                       buf->xdp = NULL;
+                       dirty++;
+                       count++;
+                       goto read_again;
+               }
 
-       res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false);
-       if (res == STMMAC_XDP_TX)
-               stmmac_flush_tx_descriptors(priv, queue);
+               /* XDP ZC Frame only support primary buffers for now */
+               buf1_len = stmmac_rx_buf1_len(priv, p, status, len);
+               len += buf1_len;
 
-       __netif_tx_unlock(nq);
+               /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
+                * Type frames (LLC/LLC-SNAP)
+                *
+                * llc_snap is never checked in GMAC >= 4, so this ACS
+                * feature is always disabled and packets need to be
+                * stripped manually.
+                */
+               if (likely(!(status & rx_not_ls)) &&
+                   (likely(priv->synopsys_id >= DWMAC_CORE_4_00) ||
+                    unlikely(status != llc_snap))) {
+                       buf1_len -= ETH_FCS_LEN;
+                       len -= ETH_FCS_LEN;
+               }
 
-       return res;
-}
+               /* RX buffer is good and fit into a XSK pool buffer */
+               buf->xdp->data_end = buf->xdp->data + buf1_len;
+               xsk_buff_dma_sync_for_cpu(buf->xdp, rx_q->xsk_pool);
 
-static struct sk_buff *stmmac_xdp_run_prog(struct stmmac_priv *priv,
-                                          struct xdp_buff *xdp)
-{
-       struct bpf_prog *prog;
-       int res;
-       u32 act;
+               rcu_read_lock();
+               prog = READ_ONCE(priv->xdp_prog);
+               res = __stmmac_xdp_run_prog(priv, prog, buf->xdp);
+               rcu_read_unlock();
 
-       rcu_read_lock();
+               switch (res) {
+               case STMMAC_XDP_PASS:
+                       stmmac_dispatch_skb_zc(priv, queue, p, np, buf->xdp);
+                       xsk_buff_free(buf->xdp);
+                       break;
+               case STMMAC_XDP_CONSUMED:
+                       xsk_buff_free(buf->xdp);
+                       priv->dev->stats.rx_dropped++;
+                       break;
+               case STMMAC_XDP_TX:
+               case STMMAC_XDP_REDIRECT:
+                       xdp_status |= res;
+                       break;
+               }
 
-       prog = READ_ONCE(priv->xdp_prog);
-       if (!prog) {
-               res = STMMAC_XDP_PASS;
-               goto unlock;
+               buf->xdp = NULL;
+               dirty++;
+               count++;
        }
 
-       act = bpf_prog_run_xdp(prog, xdp);
-       switch (act) {
-       case XDP_PASS:
-               res = STMMAC_XDP_PASS;
-               break;
-       case XDP_TX:
-               res = stmmac_xdp_xmit_back(priv, xdp);
-               break;
-       case XDP_REDIRECT:
-               if (xdp_do_redirect(priv->dev, xdp, prog) < 0)
-                       res = STMMAC_XDP_CONSUMED;
-               else
-                       res = STMMAC_XDP_REDIRECT;
-               break;
-       default:
-               bpf_warn_invalid_xdp_action(act);
-               fallthrough;
-       case XDP_ABORTED:
-               trace_xdp_exception(priv->dev, prog, act);
-               fallthrough;
-       case XDP_DROP:
-               res = STMMAC_XDP_CONSUMED;
-               break;
+       if (status & rx_not_ls) {
+               rx_q->state_saved = true;
+               rx_q->state.error = error;
+               rx_q->state.len = len;
        }
 
-unlock:
-       rcu_read_unlock();
-       return ERR_PTR(-res);
-}
-
-static void stmmac_finalize_xdp_rx(struct stmmac_priv *priv,
-                                  int xdp_status)
-{
-       int cpu = smp_processor_id();
-       int queue;
+       stmmac_finalize_xdp_rx(priv, xdp_status);
 
-       queue = stmmac_xdp_get_tx_queue(priv, cpu);
+       if (xsk_uses_need_wakeup(rx_q->xsk_pool)) {
+               if (failure || stmmac_rx_dirty(priv, queue) > 0)
+                       xsk_set_rx_need_wakeup(rx_q->xsk_pool);
+               else
+                       xsk_clear_rx_need_wakeup(rx_q->xsk_pool);
 
-       if (xdp_status & STMMAC_XDP_TX)
-               stmmac_tx_timer_arm(priv, queue);
+               return (int)count;
+       }
 
-       if (xdp_status & STMMAC_XDP_REDIRECT)
-               xdp_do_flush();
+       return failure ? limit : (int)count;
 }
 
 /**
@@ -4742,7 +5404,7 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
 
        priv->xstats.napi_poll++;
 
-       work_done = stmmac_tx_clean(priv, priv->dma_tx_size, chan);
+       work_done = stmmac_tx_clean(priv, budget, chan);
        work_done = min(work_done, budget);
 
        if (work_done < budget && napi_complete_done(napi, work_done)) {
@@ -4756,6 +5418,42 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
        return work_done;
 }
 
+static int stmmac_napi_poll_rxtx(struct napi_struct *napi, int budget)
+{
+       struct stmmac_channel *ch =
+               container_of(napi, struct stmmac_channel, rxtx_napi);
+       struct stmmac_priv *priv = ch->priv_data;
+       int rx_done, tx_done;
+       u32 chan = ch->index;
+
+       priv->xstats.napi_poll++;
+
+       tx_done = stmmac_tx_clean(priv, budget, chan);
+       tx_done = min(tx_done, budget);
+
+       rx_done = stmmac_rx_zc(priv, budget, chan);
+
+       /* If either TX or RX work is not complete, return budget
+        * and keep pooling
+        */
+       if (tx_done >= budget || rx_done >= budget)
+               return budget;
+
+       /* all work done, exit the polling mode */
+       if (napi_complete_done(napi, rx_done)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&ch->lock, flags);
+               /* Both RX and TX work done are compelte,
+                * so enable both RX & TX IRQs.
+                */
+               stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
+               spin_unlock_irqrestore(&ch->lock, flags);
+       }
+
+       return min(rx_done, budget - 1);
+}
+
 /**
  *  stmmac_tx_timeout
  *  @dev : Pointer to net device structure
@@ -4989,6 +5687,8 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv)
                        else
                                netif_carrier_off(priv->dev);
                }
+
+               stmmac_timestamp_interrupt(priv, priv);
        }
 }
 
@@ -5203,7 +5903,7 @@ static int stmmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
        if (!tc_cls_can_offload_and_chain0(priv->dev, type_data))
                return ret;
 
-       stmmac_disable_all_queues(priv);
+       __stmmac_disable_all_queues(priv);
 
        switch (type) {
        case TC_SETUP_CLSU32:
@@ -5624,6 +6324,9 @@ static int stmmac_bpf(struct net_device *dev, struct netdev_bpf *bpf)
        switch (bpf->command) {
        case XDP_SETUP_PROG:
                return stmmac_xdp_set_prog(priv, bpf->prog, bpf->extack);
+       case XDP_SETUP_XSK_POOL:
+               return stmmac_xdp_setup_pool(priv, bpf->xsk.pool,
+                                            bpf->xsk.queue_id);
        default:
                return -EOPNOTSUPP;
        }
@@ -5671,6 +6374,156 @@ static int stmmac_xdp_xmit(struct net_device *dev, int num_frames,
        return nxmit;
 }
 
+void stmmac_disable_rx_queue(struct stmmac_priv *priv, u32 queue)
+{
+       struct stmmac_channel *ch = &priv->channel[queue];
+       unsigned long flags;
+
+       spin_lock_irqsave(&ch->lock, flags);
+       stmmac_disable_dma_irq(priv, priv->ioaddr, queue, 1, 0);
+       spin_unlock_irqrestore(&ch->lock, flags);
+
+       stmmac_stop_rx_dma(priv, queue);
+       __free_dma_rx_desc_resources(priv, queue);
+}
+
+void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue)
+{
+       struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+       struct stmmac_channel *ch = &priv->channel[queue];
+       unsigned long flags;
+       u32 buf_size;
+       int ret;
+
+       ret = __alloc_dma_rx_desc_resources(priv, queue);
+       if (ret) {
+               netdev_err(priv->dev, "Failed to alloc RX desc.\n");
+               return;
+       }
+
+       ret = __init_dma_rx_desc_rings(priv, queue, GFP_KERNEL);
+       if (ret) {
+               __free_dma_rx_desc_resources(priv, queue);
+               netdev_err(priv->dev, "Failed to init RX desc.\n");
+               return;
+       }
+
+       stmmac_clear_rx_descriptors(priv, queue);
+
+       stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg,
+                           rx_q->dma_rx_phy, rx_q->queue_index);
+
+       rx_q->rx_tail_addr = rx_q->dma_rx_phy + (rx_q->buf_alloc_num *
+                            sizeof(struct dma_desc));
+       stmmac_set_rx_tail_ptr(priv, priv->ioaddr,
+                              rx_q->rx_tail_addr, rx_q->queue_index);
+
+       if (rx_q->xsk_pool && rx_q->buf_alloc_num) {
+               buf_size = xsk_pool_get_rx_frame_size(rx_q->xsk_pool);
+               stmmac_set_dma_bfsize(priv, priv->ioaddr,
+                                     buf_size,
+                                     rx_q->queue_index);
+       } else {
+               stmmac_set_dma_bfsize(priv, priv->ioaddr,
+                                     priv->dma_buf_sz,
+                                     rx_q->queue_index);
+       }
+
+       stmmac_start_rx_dma(priv, queue);
+
+       spin_lock_irqsave(&ch->lock, flags);
+       stmmac_enable_dma_irq(priv, priv->ioaddr, queue, 1, 0);
+       spin_unlock_irqrestore(&ch->lock, flags);
+}
+
+void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue)
+{
+       struct stmmac_channel *ch = &priv->channel[queue];
+       unsigned long flags;
+
+       spin_lock_irqsave(&ch->lock, flags);
+       stmmac_disable_dma_irq(priv, priv->ioaddr, queue, 0, 1);
+       spin_unlock_irqrestore(&ch->lock, flags);
+
+       stmmac_stop_tx_dma(priv, queue);
+       __free_dma_tx_desc_resources(priv, queue);
+}
+
+void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue)
+{
+       struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
+       struct stmmac_channel *ch = &priv->channel[queue];
+       unsigned long flags;
+       int ret;
+
+       ret = __alloc_dma_tx_desc_resources(priv, queue);
+       if (ret) {
+               netdev_err(priv->dev, "Failed to alloc TX desc.\n");
+               return;
+       }
+
+       ret = __init_dma_tx_desc_rings(priv, queue);
+       if (ret) {
+               __free_dma_tx_desc_resources(priv, queue);
+               netdev_err(priv->dev, "Failed to init TX desc.\n");
+               return;
+       }
+
+       stmmac_clear_tx_descriptors(priv, queue);
+
+       stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg,
+                           tx_q->dma_tx_phy, tx_q->queue_index);
+
+       if (tx_q->tbs & STMMAC_TBS_AVAIL)
+               stmmac_enable_tbs(priv, priv->ioaddr, 1, tx_q->queue_index);
+
+       tx_q->tx_tail_addr = tx_q->dma_tx_phy;
+       stmmac_set_tx_tail_ptr(priv, priv->ioaddr,
+                              tx_q->tx_tail_addr, tx_q->queue_index);
+
+       stmmac_start_tx_dma(priv, queue);
+
+       spin_lock_irqsave(&ch->lock, flags);
+       stmmac_enable_dma_irq(priv, priv->ioaddr, queue, 0, 1);
+       spin_unlock_irqrestore(&ch->lock, flags);
+}
+
+int stmmac_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       struct stmmac_rx_queue *rx_q;
+       struct stmmac_tx_queue *tx_q;
+       struct stmmac_channel *ch;
+
+       if (test_bit(STMMAC_DOWN, &priv->state) ||
+           !netif_carrier_ok(priv->dev))
+               return -ENETDOWN;
+
+       if (!stmmac_xdp_is_enabled(priv))
+               return -ENXIO;
+
+       if (queue >= priv->plat->rx_queues_to_use ||
+           queue >= priv->plat->tx_queues_to_use)
+               return -EINVAL;
+
+       rx_q = &priv->rx_queue[queue];
+       tx_q = &priv->tx_queue[queue];
+       ch = &priv->channel[queue];
+
+       if (!rx_q->xsk_pool && !tx_q->xsk_pool)
+               return -ENXIO;
+
+       if (!napi_if_scheduled_mark_missed(&ch->rxtx_napi)) {
+               /* EQoS does not have per-DMA channel SW interrupt,
+                * so we schedule RX Napi straight-away.
+                */
+               if (likely(napi_schedule_prep(&ch->rxtx_napi)))
+                       __napi_schedule(&ch->rxtx_napi);
+       }
+
+       return 0;
+}
+
 static const struct net_device_ops stmmac_netdev_ops = {
        .ndo_open = stmmac_open,
        .ndo_start_xmit = stmmac_xmit,
@@ -5691,6 +6544,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
        .ndo_vlan_rx_kill_vid = stmmac_vlan_rx_kill_vid,
        .ndo_bpf = stmmac_bpf,
        .ndo_xdp_xmit = stmmac_xdp_xmit,
+       .ndo_xsk_wakeup = stmmac_xsk_wakeup,
 };
 
 static void stmmac_reset_subtask(struct stmmac_priv *priv)
@@ -5849,6 +6703,12 @@ static void stmmac_napi_add(struct net_device *dev)
                                          stmmac_napi_poll_tx,
                                          NAPI_POLL_WEIGHT);
                }
+               if (queue < priv->plat->rx_queues_to_use &&
+                   queue < priv->plat->tx_queues_to_use) {
+                       netif_napi_add(dev, &ch->rxtx_napi,
+                                      stmmac_napi_poll_rxtx,
+                                      NAPI_POLL_WEIGHT);
+               }
        }
 }
 
@@ -5866,6 +6726,10 @@ static void stmmac_napi_del(struct net_device *dev)
                        netif_napi_del(&ch->rx_napi);
                if (queue < priv->plat->tx_queues_to_use)
                        netif_napi_del(&ch->tx_napi);
+               if (queue < priv->plat->rx_queues_to_use &&
+                   queue < priv->plat->tx_queues_to_use) {
+                       netif_napi_del(&ch->rxtx_napi);
+               }
        }
 }
 
@@ -6016,7 +6880,7 @@ int stmmac_dvr_probe(struct device *device,
        for (i = 0; i < MTL_MAX_TX_QUEUES; i++)
                priv->tx_irq[i] = res->tx_irq[i];
 
-       if (!IS_ERR_OR_NULL(res->mac))
+       if (!is_zero_ether_addr(res->mac))
                memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
 
        dev_set_drvdata(device, priv->dev);
@@ -6024,6 +6888,10 @@ int stmmac_dvr_probe(struct device *device,
        /* Verify driver arguments */
        stmmac_verify_args();
 
+       priv->af_xdp_zc_qps = bitmap_zalloc(MTL_MAX_TX_QUEUES, GFP_KERNEL);
+       if (!priv->af_xdp_zc_qps)
+               return -ENOMEM;
+
        /* Allocate workqueue */
        priv->wq = create_singlethread_workqueue("stmmac_wq");
        if (!priv->wq) {
index 5a1e018..1e17a23 100644 (file)
@@ -394,7 +394,7 @@ static int stmmac_of_get_mac_mode(struct device_node *np)
  * set some private fields that will be used by the main at runtime.
  */
 struct plat_stmmacenet_data *
-stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
+stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
 {
        struct device_node *np = pdev->dev.of_node;
        struct plat_stmmacenet_data *plat;
@@ -406,12 +406,12 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
        if (!plat)
                return ERR_PTR(-ENOMEM);
 
-       *mac = of_get_mac_address(np);
-       if (IS_ERR(*mac)) {
-               if (PTR_ERR(*mac) == -EPROBE_DEFER)
-                       return ERR_CAST(*mac);
+       rc = of_get_mac_address(np, mac);
+       if (rc) {
+               if (rc == -EPROBE_DEFER)
+                       return ERR_PTR(rc);
 
-               *mac = NULL;
+               eth_zero_addr(mac);
        }
 
        plat->phy_interface = device_get_phy_mode(&pdev->dev);
@@ -627,7 +627,7 @@ void stmmac_remove_config_dt(struct platform_device *pdev,
 }
 #else
 struct plat_stmmacenet_data *
-stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
+stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
 {
        return ERR_PTR(-EINVAL);
 }
index 3a4663b..3fff3f5 100644 (file)
@@ -12,7 +12,7 @@
 #include "stmmac.h"
 
 struct plat_stmmacenet_data *
-stmmac_probe_config_dt(struct platform_device *pdev, const char **mac);
+stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac);
 void stmmac_remove_config_dt(struct platform_device *pdev,
                             struct plat_stmmacenet_data *plat);
 
index b164ae2..4e86cdf 100644 (file)
@@ -135,7 +135,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
 {
        struct stmmac_priv *priv =
            container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+       void __iomem *ptpaddr = priv->ptpaddr;
+       void __iomem *ioaddr = priv->hw->pcsr;
        struct stmmac_pps_cfg *cfg;
+       u32 intr_value, acr_value;
        int ret = -EOPNOTSUPP;
        unsigned long flags;
 
@@ -159,6 +162,37 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
                                             priv->systime_flags);
                spin_unlock_irqrestore(&priv->ptp_lock, flags);
                break;
+       case PTP_CLK_REQ_EXTTS:
+               priv->plat->ext_snapshot_en = on;
+               mutex_lock(&priv->aux_ts_lock);
+               acr_value = readl(ptpaddr + PTP_ACR);
+               acr_value &= ~PTP_ACR_MASK;
+               if (on) {
+                       /* Enable External snapshot trigger */
+                       acr_value |= priv->plat->ext_snapshot_num;
+                       acr_value |= PTP_ACR_ATSFC;
+                       netdev_dbg(priv->dev, "Auxiliary Snapshot %d enabled.\n",
+                                  priv->plat->ext_snapshot_num >>
+                                  PTP_ACR_ATSEN_SHIFT);
+                       /* Enable Timestamp Interrupt */
+                       intr_value = readl(ioaddr + GMAC_INT_EN);
+                       intr_value |= GMAC_INT_TSIE;
+                       writel(intr_value, ioaddr + GMAC_INT_EN);
+
+               } else {
+                       netdev_dbg(priv->dev, "Auxiliary Snapshot %d disabled.\n",
+                                  priv->plat->ext_snapshot_num >>
+                                  PTP_ACR_ATSEN_SHIFT);
+                       /* Disable Timestamp Interrupt */
+                       intr_value = readl(ioaddr + GMAC_INT_EN);
+                       intr_value &= ~GMAC_INT_TSIE;
+                       writel(intr_value, ioaddr + GMAC_INT_EN);
+               }
+               writel(acr_value, ptpaddr + PTP_ACR);
+               mutex_unlock(&priv->aux_ts_lock);
+               ret = 0;
+               break;
+
        default:
                break;
        }
@@ -202,7 +236,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {
        .name = "stmmac ptp",
        .max_adj = 62500000,
        .n_alarm = 0,
-       .n_ext_ts = 0,
+       .n_ext_ts = 0, /* will be overwritten in stmmac_ptp_register */
        .n_per_out = 0, /* will be overwritten in stmmac_ptp_register */
        .n_pins = 0,
        .pps = 0,
@@ -237,8 +271,10 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
                stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
 
        stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
+       stmmac_ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n;
 
        spin_lock_init(&priv->ptp_lock);
+       mutex_init(&priv->aux_ts_lock);
        priv->ptp_clock_ops = stmmac_ptp_clock_ops;
 
        priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
@@ -264,4 +300,6 @@ void stmmac_ptp_unregister(struct stmmac_priv *priv)
                pr_debug("Removed PTP HW clock successfully on %s\n",
                         priv->dev->name);
        }
+
+       mutex_destroy(&priv->aux_ts_lock);
 }
index f88727c..53172a4 100644 (file)
@@ -73,6 +73,7 @@
 #define        PTP_ACR_ATSEN1          BIT(5)  /* Auxiliary Snapshot 1 Enable */
 #define        PTP_ACR_ATSEN2          BIT(6)  /* Auxiliary Snapshot 2 Enable */
 #define        PTP_ACR_ATSEN3          BIT(7)  /* Auxiliary Snapshot 3 Enable */
+#define        PTP_ACR_ATSEN_SHIFT     5       /* Auxiliary Snapshot shift */
 #define        PTP_ACR_MASK            GENMASK(7, 4)   /* Aux Snapshot Mask */
 #define        PMC_ART_VALUE0          0x01    /* PMC_ART[15:0] timer value */
 #define        PMC_ART_VALUE1          0x02    /* PMC_ART[31:16] timer value */
index bf38d23..105821b 100644 (file)
@@ -1,9 +1,104 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright (c) 2021, Intel Corporation. */
 
+#include <net/xdp_sock_drv.h>
+
 #include "stmmac.h"
 #include "stmmac_xdp.h"
 
+static int stmmac_xdp_enable_pool(struct stmmac_priv *priv,
+                                 struct xsk_buff_pool *pool, u16 queue)
+{
+       struct stmmac_channel *ch = &priv->channel[queue];
+       bool need_update;
+       u32 frame_size;
+       int err;
+
+       if (queue >= priv->plat->rx_queues_to_use ||
+           queue >= priv->plat->tx_queues_to_use)
+               return -EINVAL;
+
+       frame_size = xsk_pool_get_rx_frame_size(pool);
+       /* XDP ZC does not span multiple frame, make sure XSK pool buffer
+        * size can at least store Q-in-Q frame.
+        */
+       if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2)
+               return -EOPNOTSUPP;
+
+       err = xsk_pool_dma_map(pool, priv->device, STMMAC_RX_DMA_ATTR);
+       if (err) {
+               netdev_err(priv->dev, "Failed to map xsk pool\n");
+               return err;
+       }
+
+       need_update = netif_running(priv->dev) && stmmac_xdp_is_enabled(priv);
+
+       if (need_update) {
+               stmmac_disable_rx_queue(priv, queue);
+               stmmac_disable_tx_queue(priv, queue);
+               napi_disable(&ch->rx_napi);
+               napi_disable(&ch->tx_napi);
+       }
+
+       set_bit(queue, priv->af_xdp_zc_qps);
+
+       if (need_update) {
+               napi_enable(&ch->rxtx_napi);
+               stmmac_enable_rx_queue(priv, queue);
+               stmmac_enable_tx_queue(priv, queue);
+
+               err = stmmac_xsk_wakeup(priv->dev, queue, XDP_WAKEUP_RX);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int stmmac_xdp_disable_pool(struct stmmac_priv *priv, u16 queue)
+{
+       struct stmmac_channel *ch = &priv->channel[queue];
+       struct xsk_buff_pool *pool;
+       bool need_update;
+
+       if (queue >= priv->plat->rx_queues_to_use ||
+           queue >= priv->plat->tx_queues_to_use)
+               return -EINVAL;
+
+       pool = xsk_get_pool_from_qid(priv->dev, queue);
+       if (!pool)
+               return -EINVAL;
+
+       need_update = netif_running(priv->dev) && stmmac_xdp_is_enabled(priv);
+
+       if (need_update) {
+               stmmac_disable_rx_queue(priv, queue);
+               stmmac_disable_tx_queue(priv, queue);
+               synchronize_rcu();
+               napi_disable(&ch->rxtx_napi);
+       }
+
+       xsk_pool_dma_unmap(pool, STMMAC_RX_DMA_ATTR);
+
+       clear_bit(queue, priv->af_xdp_zc_qps);
+
+       if (need_update) {
+               napi_enable(&ch->rx_napi);
+               napi_enable(&ch->tx_napi);
+               stmmac_enable_rx_queue(priv, queue);
+               stmmac_enable_tx_queue(priv, queue);
+       }
+
+       return 0;
+}
+
+int stmmac_xdp_setup_pool(struct stmmac_priv *priv, struct xsk_buff_pool *pool,
+                         u16 queue)
+{
+       return pool ? stmmac_xdp_enable_pool(priv, pool, queue) :
+                     stmmac_xdp_disable_pool(priv, queue);
+}
+
 int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog,
                        struct netlink_ext_ack *extack)
 {
index 9394856..896dc98 100644 (file)
@@ -5,7 +5,10 @@
 #define _STMMAC_XDP_H_
 
 #define STMMAC_MAX_RX_BUF_SIZE(num)    (((num) * PAGE_SIZE) - XDP_PACKET_HEADROOM)
+#define STMMAC_RX_DMA_ATTR     (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
 
+int stmmac_xdp_setup_pool(struct stmmac_priv *priv, struct xsk_buff_pool *pool,
+                         u16 queue);
 int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog,
                        struct netlink_ext_ack *extack);
 
index 638d7b0..6a67b02 100644 (file)
@@ -1824,7 +1824,6 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
 
        for_each_child_of_node(node, port_np) {
                struct am65_cpsw_port *port;
-               const void *mac_addr;
                u32 port_id;
 
                /* it is not a slave port node, continue */
@@ -1903,15 +1902,15 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
                        return ret;
                }
 
-               mac_addr = of_get_mac_address(port_np);
-               if (!IS_ERR(mac_addr)) {
-                       ether_addr_copy(port->slave.mac_addr, mac_addr);
-               } else if (am65_cpsw_am654_get_efuse_macid(port_np,
-                                                          port->port_id,
-                                                          port->slave.mac_addr) ||
-                          !is_valid_ether_addr(port->slave.mac_addr)) {
-                       random_ether_addr(port->slave.mac_addr);
-                       dev_err(dev, "Use random MAC address\n");
+               ret = of_get_mac_address(port_np, port->slave.mac_addr);
+               if (ret) {
+                       am65_cpsw_am654_get_efuse_macid(port_np,
+                                                       port->port_id,
+                                                       port->slave.mac_addr);
+                       if (!is_valid_ether_addr(port->slave.mac_addr)) {
+                               random_ether_addr(port->slave.mac_addr);
+                               dev_err(dev, "Use random MAC address\n");
+                       }
                }
        }
        of_node_put(node);
index 074702a..c0cd7de 100644 (file)
@@ -1296,7 +1296,6 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 
        for_each_available_child_of_node(node, slave_node) {
                struct cpsw_slave_data *slave_data = data->slave_data + i;
-               const void *mac_addr = NULL;
                int lenp;
                const __be32 *parp;
 
@@ -1368,10 +1367,8 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                }
 
 no_phy_slave:
-               mac_addr = of_get_mac_address(slave_node);
-               if (!IS_ERR(mac_addr)) {
-                       ether_addr_copy(slave_data->mac_addr, mac_addr);
-               } else {
+               ret = of_get_mac_address(slave_node, slave_data->mac_addr);
+               if (ret) {
                        ret = ti_cm_get_macid(&pdev->dev, i,
                                              slave_data->mac_addr);
                        if (ret)
index 0751f77..69b7a4e 100644 (file)
@@ -1257,7 +1257,6 @@ static int cpsw_probe_dt(struct cpsw_common *cpsw)
 
        for_each_child_of_node(tmp_node, port_np) {
                struct cpsw_slave_data *slave_data;
-               const void *mac_addr;
                u32 port_id;
 
                ret = of_property_read_u32(port_np, "reg", &port_id);
@@ -1316,10 +1315,8 @@ static int cpsw_probe_dt(struct cpsw_common *cpsw)
                        goto err_node_put;
                }
 
-               mac_addr = of_get_mac_address(port_np);
-               if (!IS_ERR(mac_addr)) {
-                       ether_addr_copy(slave_data->mac_addr, mac_addr);
-               } else {
+               ret = of_get_mac_address(port_np, slave_data->mac_addr);
+               if (ret) {
                        ret = ti_cm_get_macid(dev, port_id - 1,
                                              slave_data->mac_addr);
                        if (ret)
index c7031e1..14e7da7 100644 (file)
@@ -1687,7 +1687,6 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)
        const struct of_device_id *match;
        const struct emac_platform_data *auxdata;
        struct emac_platform_data *pdata = NULL;
-       const u8 *mac_addr;
 
        if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
                return dev_get_platdata(&pdev->dev);
@@ -1699,11 +1698,8 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)
        np = pdev->dev.of_node;
        pdata->version = EMAC_VERSION_2;
 
-       if (!is_valid_ether_addr(pdata->mac_addr)) {
-               mac_addr = of_get_mac_address(np);
-               if (!IS_ERR(mac_addr))
-                       ether_addr_copy(pdata->mac_addr, mac_addr);
-       }
+       if (!is_valid_ether_addr(pdata->mac_addr))
+               of_get_mac_address(np, pdata->mac_addr);
 
        of_property_read_u32(np, "ti,davinci-ctrl-reg-offset",
                             &pdata->ctrl_reg_offset);
index d7a144b..9030e61 100644 (file)
@@ -1966,7 +1966,6 @@ static int netcp_create_interface(struct netcp_device *netcp_device,
        struct resource res;
        void __iomem *efuse = NULL;
        u32 efuse_mac = 0;
-       const void *mac_addr;
        u8 efuse_mac_addr[6];
        u32 temp[2];
        int ret = 0;
@@ -2036,10 +2035,8 @@ static int netcp_create_interface(struct netcp_device *netcp_device,
                devm_iounmap(dev, efuse);
                devm_release_mem_region(dev, res.start, size);
        } else {
-               mac_addr = of_get_mac_address(node_interface);
-               if (!IS_ERR(mac_addr))
-                       ether_addr_copy(ndev->dev_addr, mac_addr);
-               else
+               ret = of_get_mac_address(node_interface, ndev->dev_addr);
+               if (ret)
                        eth_random_addr(ndev->dev_addr);
        }
 
index 2b4126d..2b84848 100644 (file)
@@ -423,8 +423,14 @@ static int w5100_spi_probe(struct spi_device *spi)
        const struct of_device_id *of_id;
        const struct w5100_ops *ops;
        kernel_ulong_t driver_data;
+       const void *mac = NULL;
+       u8 tmpmac[ETH_ALEN];
        int priv_size;
-       const void *mac = of_get_mac_address(spi->dev.of_node);
+       int ret;
+
+       ret = of_get_mac_address(spi->dev.of_node, tmpmac);
+       if (!ret)
+               mac = tmpmac;
 
        if (spi->dev.of_node) {
                of_id = of_match_device(w5100_of_match, &spi->dev);
index c0d181a..ec5db48 100644 (file)
@@ -1157,7 +1157,7 @@ int w5100_probe(struct device *dev, const struct w5100_ops *ops,
        INIT_WORK(&priv->setrx_work, w5100_setrx_work);
        INIT_WORK(&priv->restart_work, w5100_restart_work);
 
-       if (!IS_ERR_OR_NULL(mac_addr))
+       if (mac_addr)
                memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
        else
                eth_hw_addr_random(ndev);
index 0301853..a1f5f07 100644 (file)
@@ -438,7 +438,7 @@ static void temac_do_set_mac_address(struct net_device *ndev)
 
 static int temac_init_mac_address(struct net_device *ndev, const void *address)
 {
-       ether_addr_copy(ndev->dev_addr, address);
+       memcpy(ndev->dev_addr, address, ETH_ALEN);
        if (!is_valid_ether_addr(ndev->dev_addr))
                eth_hw_addr_random(ndev);
        temac_do_set_mac_address(ndev);
@@ -1351,7 +1351,7 @@ static int temac_probe(struct platform_device *pdev)
        struct device_node *temac_np = dev_of_node(&pdev->dev), *dma_np;
        struct temac_local *lp;
        struct net_device *ndev;
-       const void *addr;
+       u8 addr[ETH_ALEN];
        __be32 *p;
        bool little_endian;
        int rc = 0;
@@ -1542,8 +1542,8 @@ static int temac_probe(struct platform_device *pdev)
 
        if (temac_np) {
                /* Retrieve the MAC address */
-               addr = of_get_mac_address(temac_np);
-               if (IS_ERR(addr)) {
+               rc = of_get_mac_address(temac_np, addr);
+               if (rc) {
                        dev_err(&pdev->dev, "could not find MAC address\n");
                        return -ENODEV;
                }
index feb1aa4..b508c94 100644 (file)
@@ -1835,8 +1835,8 @@ static int axienet_probe(struct platform_device *pdev)
        struct device_node *np;
        struct axienet_local *lp;
        struct net_device *ndev;
-       const void *mac_addr;
        struct resource *ethres;
+       u8 mac_addr[ETH_ALEN];
        int addr_width = 32;
        u32 value;
 
@@ -2062,13 +2062,14 @@ static int axienet_probe(struct platform_device *pdev)
                dev_info(&pdev->dev, "Ethernet core IRQ not defined\n");
 
        /* Retrieve the MAC address */
-       mac_addr = of_get_mac_address(pdev->dev.of_node);
-       if (IS_ERR(mac_addr)) {
-               dev_warn(&pdev->dev, "could not find MAC address property: %ld\n",
-                        PTR_ERR(mac_addr));
-               mac_addr = NULL;
+       ret = of_get_mac_address(pdev->dev.of_node, mac_addr);
+       if (!ret) {
+               axienet_set_mac_address(ndev, mac_addr);
+       } else {
+               dev_warn(&pdev->dev, "could not find MAC address property: %d\n",
+                        ret);
+               axienet_set_mac_address(ndev, NULL);
        }
-       axienet_set_mac_address(ndev, mac_addr);
 
        lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
        lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
index 007840d..d9d58a7 100644 (file)
@@ -1115,7 +1115,6 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
        struct net_device *ndev = NULL;
        struct net_local *lp = NULL;
        struct device *dev = &ofdev->dev;
-       const void *mac_address;
 
        int rc = 0;
 
@@ -1157,12 +1156,9 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
        lp->next_rx_buf_to_use = 0x0;
        lp->tx_ping_pong = get_bool(ofdev, "xlnx,tx-ping-pong");
        lp->rx_ping_pong = get_bool(ofdev, "xlnx,rx-ping-pong");
-       mac_address = of_get_mac_address(ofdev->dev.of_node);
 
-       if (!IS_ERR(mac_address)) {
-               /* Set the MAC address. */
-               ether_addr_copy(ndev->dev_addr, mac_address);
-       } else {
+       rc = of_get_mac_address(ofdev->dev.of_node, ndev->dev_addr);
+       if (rc) {
                dev_warn(dev, "No MAC address found, using random\n");
                eth_hw_addr_random(ndev);
        }
index 8c0ac87..1efe1a8 100644 (file)
@@ -10,4 +10,5 @@ ipa-y                 :=      ipa_main.o ipa_clock.o ipa_reg.o ipa_mem.o \
                                ipa_resource.o ipa_qmi.o ipa_qmi_msg.o
 
 ipa-y                  +=      ipa_data-v3.5.1.o ipa_data-v4.2.o \
-                               ipa_data-v4.5.o ipa_data-v4.11.o
+                               ipa_data-v4.5.o ipa_data-v4.9.o \
+                               ipa_data-v4.11.o
diff --git a/drivers/net/ipa/ipa_data-v4.9.c b/drivers/net/ipa/ipa_data-v4.9.c
new file mode 100644 (file)
index 0000000..e41be79
--- /dev/null
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Copyright (C) 2021 Linaro Ltd. */
+
+#include <linux/log2.h>
+
+#include "gsi.h"
+#include "ipa_data.h"
+#include "ipa_endpoint.h"
+#include "ipa_mem.h"
+
+/** enum ipa_resource_type - IPA resource types for an SoC having IPA v4.9 */
+enum ipa_resource_type {
+       /* Source resource types; first must have value 0 */
+       IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS              = 0,
+       IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
+       IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
+       IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
+       IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
+
+       /* Destination resource types; first must have value 0 */
+       IPA_RESOURCE_TYPE_DST_DATA_SECTORS              = 0,
+       IPA_RESOURCE_TYPE_DST_DPS_DMARS,
+};
+
+/* Resource groups used for an SoC having IPA v4.9 */
+enum ipa_rsrc_group_id {
+       /* Source resource group identifiers */
+       IPA_RSRC_GROUP_SRC_UL_DL                        = 0,
+       IPA_RSRC_GROUP_SRC_DMA,
+       IPA_RSRC_GROUP_SRC_UC_RX_Q,
+       IPA_RSRC_GROUP_SRC_COUNT,       /* Last in set; not a source group */
+
+       /* Destination resource group identifiers */
+       IPA_RSRC_GROUP_DST_UL_DL_DPL                    = 0,
+       IPA_RSRC_GROUP_DST_DMA,
+       IPA_RSRC_GROUP_DST_UC,
+       IPA_RSRC_GROUP_DST_DRB_IP,
+       IPA_RSRC_GROUP_DST_COUNT,       /* Last; not a destination group */
+};
+
+/* QSB configuration data for an SoC having IPA v4.9 */
+static const struct ipa_qsb_data ipa_qsb_data[] = {
+       [IPA_QSB_MASTER_DDR] = {
+               .max_writes             = 8,
+               .max_reads              = 0,    /* no limit (hardware max) */
+               .max_reads_beats        = 120,
+       },
+};
+
+/* Endpoint configuration data for an SoC having IPA v4.9 */
+static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
+       [IPA_ENDPOINT_AP_COMMAND_TX] = {
+               .ee_id          = GSI_EE_AP,
+               .channel_id     = 6,
+               .endpoint_id    = 7,
+               .toward_ipa     = true,
+               .channel = {
+                       .tre_count      = 256,
+                       .event_count    = 256,
+                       .tlv_count      = 20,
+               },
+               .endpoint = {
+                       .config = {
+                               .resource_group = IPA_RSRC_GROUP_SRC_UL_DL,
+                               .dma_mode       = true,
+                               .dma_endpoint   = IPA_ENDPOINT_AP_LAN_RX,
+                               .tx = {
+                                       .seq_type = IPA_SEQ_DMA,
+                               },
+                       },
+               },
+       },
+       [IPA_ENDPOINT_AP_LAN_RX] = {
+               .ee_id          = GSI_EE_AP,
+               .channel_id     = 7,
+               .endpoint_id    = 11,
+               .toward_ipa     = false,
+               .channel = {
+                       .tre_count      = 256,
+                       .event_count    = 256,
+                       .tlv_count      = 9,
+               },
+               .endpoint = {
+                       .config = {
+                               .resource_group = IPA_RSRC_GROUP_DST_UL_DL_DPL,
+                               .aggregation    = true,
+                               .status_enable  = true,
+                               .rx = {
+                                       .pad_align      = ilog2(sizeof(u32)),
+                               },
+                       },
+               },
+       },
+       [IPA_ENDPOINT_AP_MODEM_TX] = {
+               .ee_id          = GSI_EE_AP,
+               .channel_id     = 2,
+               .endpoint_id    = 2,
+               .toward_ipa     = true,
+               .channel = {
+                       .tre_count      = 512,
+                       .event_count    = 512,
+                       .tlv_count      = 16,
+               },
+               .endpoint = {
+                       .filter_support = true,
+                       .config = {
+                               .resource_group = IPA_RSRC_GROUP_SRC_UL_DL,
+                               .qmap           = true,
+                               .status_enable  = true,
+                               .tx = {
+                                       .seq_type = IPA_SEQ_2_PASS_SKIP_LAST_UC,
+                                       .status_endpoint =
+                                               IPA_ENDPOINT_MODEM_AP_RX,
+                               },
+                       },
+               },
+       },
+       [IPA_ENDPOINT_AP_MODEM_RX] = {
+               .ee_id          = GSI_EE_AP,
+               .channel_id     = 12,
+               .endpoint_id    = 20,
+               .toward_ipa     = false,
+               .channel = {
+                       .tre_count      = 256,
+                       .event_count    = 256,
+                       .tlv_count      = 9,
+               },
+               .endpoint = {
+                       .config = {
+                               .resource_group = IPA_RSRC_GROUP_DST_UL_DL_DPL,
+                               .qmap           = true,
+                               .aggregation    = true,
+                               .rx = {
+                                       .aggr_close_eof = true,
+                               },
+                       },
+               },
+       },
+       [IPA_ENDPOINT_MODEM_AP_TX] = {
+               .ee_id          = GSI_EE_MODEM,
+               .channel_id     = 0,
+               .endpoint_id    = 5,
+               .toward_ipa     = true,
+               .endpoint = {
+                       .filter_support = true,
+               },
+       },
+       [IPA_ENDPOINT_MODEM_AP_RX] = {
+               .ee_id          = GSI_EE_MODEM,
+               .channel_id     = 7,
+               .endpoint_id    = 16,
+               .toward_ipa     = false,
+       },
+       [IPA_ENDPOINT_MODEM_DL_NLO_TX] = {
+               .ee_id          = GSI_EE_MODEM,
+               .channel_id     = 2,
+               .endpoint_id    = 8,
+               .toward_ipa     = true,
+               .endpoint = {
+                       .filter_support = true,
+               },
+       },
+};
+
+/* Source resource configuration data for an SoC having IPA v4.9 */
+static const struct ipa_resource ipa_resource_src[] = {
+       [IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS] = {
+               .limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
+                       .min = 1,       .max = 12,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+                       .min = 1,       .max = 1,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+                       .min = 1,       .max = 12,
+               },
+       },
+       [IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS] = {
+               .limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
+                       .min = 20,      .max = 20,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+                       .min = 2,       .max = 2,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+                       .min = 3,       .max = 3,
+               },
+       },
+       [IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF] = {
+               .limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
+                       .min = 38,      .max = 38,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+                       .min = 4,       .max = 4,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+                       .min = 8,       .max = 8,
+               },
+       },
+       [IPA_RESOURCE_TYPE_SRC_HPS_DMARS] = {
+               .limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
+                       .min = 0,       .max = 4,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+                       .min = 0,       .max = 4,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+                       .min = 0,       .max = 4,
+               },
+       },
+       [IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES] = {
+               .limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
+                       .min = 30,      .max = 30,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+                       .min = 8,       .max = 8,
+               },
+               .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+                       .min = 8,       .max = 8,
+               },
+       },
+};
+
+/* Destination resource configuration data for an SoC having IPA v4.9 */
+static const struct ipa_resource ipa_resource_dst[] = {
+       [IPA_RESOURCE_TYPE_DST_DATA_SECTORS] = {
+               .limits[IPA_RSRC_GROUP_DST_UL_DL_DPL] = {
+                       .min = 9,       .max = 9,
+               },
+               .limits[IPA_RSRC_GROUP_DST_DMA] = {
+                       .min = 1,       .max = 1,
+               },
+               .limits[IPA_RSRC_GROUP_DST_UC] = {
+                       .min = 1,       .max = 1,
+               },
+               .limits[IPA_RSRC_GROUP_DST_DRB_IP] = {
+                       .min = 39,      .max = 39,
+               },
+       },
+       [IPA_RESOURCE_TYPE_DST_DPS_DMARS] = {
+               .limits[IPA_RSRC_GROUP_DST_UL_DL_DPL] = {
+                       .min = 2,       .max = 3,
+               },
+               .limits[IPA_RSRC_GROUP_DST_DMA] = {
+                       .min = 1,       .max = 2,
+               },
+               .limits[IPA_RSRC_GROUP_DST_UC] = {
+                       .min = 0,       .max = 2,
+               },
+       },
+};
+
+/* Resource configuration data for an SoC having IPA v4.9 */
+static const struct ipa_resource_data ipa_resource_data = {
+       .rsrc_group_dst_count   = IPA_RSRC_GROUP_DST_COUNT,
+       .rsrc_group_src_count   = IPA_RSRC_GROUP_SRC_COUNT,
+       .resource_src_count     = ARRAY_SIZE(ipa_resource_src),
+       .resource_src           = ipa_resource_src,
+       .resource_dst_count     = ARRAY_SIZE(ipa_resource_dst),
+       .resource_dst           = ipa_resource_dst,
+};
+
+/* IPA-resident memory region data for an SoC having IPA v4.9 */
+static const struct ipa_mem ipa_mem_local_data[] = {
+       [IPA_MEM_UC_SHARED] = {
+               .offset         = 0x0000,
+               .size           = 0x0080,
+               .canary_count   = 0,
+       },
+       [IPA_MEM_UC_INFO] = {
+               .offset         = 0x0080,
+               .size           = 0x0200,
+               .canary_count   = 0,
+       },
+       [IPA_MEM_V4_FILTER_HASHED] = { .offset          = 0x0288,
+               .size           = 0x0078,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_V4_FILTER] = {
+               .offset         = 0x0308,
+               .size           = 0x0078,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_V6_FILTER_HASHED] = {
+               .offset         = 0x0388,
+               .size           = 0x0078,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_V6_FILTER] = {
+               .offset         = 0x0408,
+               .size           = 0x0078,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_V4_ROUTE_HASHED] = {
+               .offset         = 0x0488,
+               .size           = 0x0078,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_V4_ROUTE] = {
+               .offset         = 0x0508,
+               .size           = 0x0078,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_V6_ROUTE_HASHED] = {
+               .offset         = 0x0588,
+               .size           = 0x0078,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_V6_ROUTE] = {
+               .offset         = 0x0608,
+               .size           = 0x0078,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_MODEM_HEADER] = {
+               .offset         = 0x0688,
+               .size           = 0x0240,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_AP_HEADER] = {
+               .offset         = 0x08c8,
+               .size           = 0x0200,
+               .canary_count   = 0,
+       },
+       [IPA_MEM_MODEM_PROC_CTX] = {
+               .offset         = 0x0ad0,
+               .size           = 0x0b20,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_AP_PROC_CTX] = {
+               .offset         = 0x15f0,
+               .size           = 0x0200,
+               .canary_count   = 0,
+       },
+       [IPA_MEM_NAT_TABLE] = {
+               .offset         = 0x1800,
+               .size           = 0x0d00,
+               .canary_count   = 4,
+       },
+       [IPA_MEM_STATS_QUOTA_MODEM] = {
+               .offset         = 0x2510,
+               .size           = 0x0030,
+               .canary_count   = 4,
+       },
+       [IPA_MEM_STATS_QUOTA_AP] = {
+               .offset         = 0x2540,
+               .size           = 0x0048,
+               .canary_count   = 0,
+       },
+       [IPA_MEM_STATS_TETHERING] = {
+               .offset         = 0x2588,
+               .size           = 0x0238,
+               .canary_count   = 0,
+       },
+       [IPA_MEM_STATS_FILTER_ROUTE] = {
+               .offset         = 0x27c0,
+               .size           = 0x0800,
+               .canary_count   = 0,
+       },
+       [IPA_MEM_STATS_DROP] = {
+               .offset         = 0x2fc0,
+               .size           = 0x0020,
+               .canary_count   = 0,
+       },
+       [IPA_MEM_MODEM] = {
+               .offset         = 0x2fe8,
+               .size           = 0x0800,
+               .canary_count   = 2,
+       },
+       [IPA_MEM_UC_EVENT_RING] = {
+               .offset         = 0x3800,
+               .size           = 0x1000,
+               .canary_count   = 1,
+       },
+       [IPA_MEM_PDN_CONFIG] = {
+               .offset         = 0x4800,
+               .size           = 0x0050,
+               .canary_count   = 0,
+       },
+};
+
+/* Memory configuration data for an SoC having IPA v4.9 */
+static const struct ipa_mem_data ipa_mem_data = {
+       .local_count    = ARRAY_SIZE(ipa_mem_local_data),
+       .local          = ipa_mem_local_data,
+       .imem_addr      = 0x146bd000,
+       .imem_size      = 0x00002000,
+       .smem_id        = 497,
+       .smem_size      = 0x00009000,
+};
+
+/* Interconnect rates are in 1000 byte/second units */
+static const struct ipa_interconnect_data ipa_interconnect_data[] = {
+       {
+               .name                   = "ipa_to_llcc",
+               .peak_bandwidth         = 600000,       /* 600 MBps */
+               .average_bandwidth      = 150000,       /* 150 MBps */
+       },
+       {
+               .name                   = "llcc_to_ebi1",
+               .peak_bandwidth         = 1804000,      /* 1.804 GBps */
+               .average_bandwidth      = 150000,       /* 150 MBps */
+       },
+       /* Average rate is unused for the next interconnect */
+       {
+               .name                   = "appss_to_ipa",
+               .peak_bandwidth         = 74000,        /* 74 MBps */
+               .average_bandwidth      = 0,            /* unused */
+       },
+
+};
+
+/* Clock and interconnect configuration data for an SoC having IPA v4.9 */
+static const struct ipa_clock_data ipa_clock_data = {
+       .core_clock_rate        = 60 * 1000 * 1000,     /* Hz */
+       .interconnect_count     = ARRAY_SIZE(ipa_interconnect_data),
+       .interconnect_data      = ipa_interconnect_data,
+};
+
+/* Configuration data for an SoC having IPA v4.9. */
+const struct ipa_data ipa_data_v4_9 = {
+       .version        = IPA_VERSION_4_9,
+       .qsb_count      = ARRAY_SIZE(ipa_qsb_data),
+       .qsb_data       = ipa_qsb_data,
+       .endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
+       .endpoint_data  = ipa_gsi_endpoint_data,
+       .resource_data  = &ipa_resource_data,
+       .mem_data       = &ipa_mem_data,
+       .clock_data     = &ipa_clock_data,
+};
index e3212ea..5c4c8d7 100644 (file)
@@ -303,6 +303,7 @@ struct ipa_data {
 extern const struct ipa_data ipa_data_v3_5_1;
 extern const struct ipa_data ipa_data_v4_2;
 extern const struct ipa_data ipa_data_v4_5;
+extern const struct ipa_data ipa_data_v4_9;
 extern const struct ipa_data ipa_data_v4_11;
 
 #endif /* _IPA_DATA_H_ */
index 0d168af..aad915e 100644 (file)
@@ -577,6 +577,10 @@ static const struct of_device_id ipa_match[] = {
                .compatible     = "qcom,sdx55-ipa",
                .data           = &ipa_data_v4_5,
        },
+       {
+               .compatible     = "qcom,sm8350-ipa",
+               .data           = &ipa_data_v4_9,
+       },
        {
                .compatible     = "qcom,sc7280-ipa",
                .data           = &ipa_data_v4_11,
index eca8c2f..9b9ac3e 100644 (file)
 #define        MV_HOST_RST_SW  BIT(7)
 #define        MV_PORT_RST_SW  (MV_LINE_RST_SW | MV_HOST_RST_SW)
 
+/* PMD Receive Signal Detect */
+#define        MV_RX_SIGNAL_DETECT             0x000A
+#define        MV_RX_SIGNAL_DETECT_GLOBAL      BIT(0)
+
 /* 1000Base-X/SGMII Control Register */
 #define        MV_1GBX_CTRL            (0x2000 + MII_BMCR)
 
 #define        MV_1GBX_PHY_STAT_SPEED100       BIT(14)
 #define        MV_1GBX_PHY_STAT_SPEED1000      BIT(15)
 
+#define        AUTONEG_TIMEOUT 3
+
 struct mv2222_data {
        phy_interface_t line_interface;
        __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+       bool sfp_link;
 };
 
 /* SFI PMA transmit enable */
@@ -81,86 +88,6 @@ static int mv2222_soft_reset(struct phy_device *phydev)
                                         5000, 1000000, true);
 }
 
-/* Returns negative on error, 0 if link is down, 1 if link is up */
-static int mv2222_read_status_10g(struct phy_device *phydev)
-{
-       int val, link = 0;
-
-       val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
-       if (val < 0)
-               return val;
-
-       if (val & MDIO_STAT1_LSTATUS) {
-               link = 1;
-
-               /* 10GBASE-R do not support auto-negotiation */
-               phydev->autoneg = AUTONEG_DISABLE;
-               phydev->speed = SPEED_10000;
-               phydev->duplex = DUPLEX_FULL;
-       }
-
-       return link;
-}
-
-/* Returns negative on error, 0 if link is down, 1 if link is up */
-static int mv2222_read_status_1g(struct phy_device *phydev)
-{
-       int val, link = 0;
-
-       val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
-       if (val < 0)
-               return val;
-
-       if (!(val & BMSR_LSTATUS) ||
-           (phydev->autoneg == AUTONEG_ENABLE &&
-            !(val & BMSR_ANEGCOMPLETE)))
-               return 0;
-
-       link = 1;
-
-       val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_PHY_STAT);
-       if (val < 0)
-               return val;
-
-       if (val & MV_1GBX_PHY_STAT_AN_RESOLVED) {
-               if (val & MV_1GBX_PHY_STAT_DUPLEX)
-                       phydev->duplex = DUPLEX_FULL;
-               else
-                       phydev->duplex = DUPLEX_HALF;
-
-               if (val & MV_1GBX_PHY_STAT_SPEED1000)
-                       phydev->speed = SPEED_1000;
-               else if (val & MV_1GBX_PHY_STAT_SPEED100)
-                       phydev->speed = SPEED_100;
-               else
-                       phydev->speed = SPEED_10;
-       }
-
-       return link;
-}
-
-static int mv2222_read_status(struct phy_device *phydev)
-{
-       struct mv2222_data *priv = phydev->priv;
-       int link;
-
-       phydev->link = 0;
-       phydev->speed = SPEED_UNKNOWN;
-       phydev->duplex = DUPLEX_UNKNOWN;
-
-       if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
-               link = mv2222_read_status_10g(phydev);
-       else
-               link = mv2222_read_status_1g(phydev);
-
-       if (link < 0)
-               return link;
-
-       phydev->link = link;
-
-       return 0;
-}
-
 static int mv2222_disable_aneg(struct phy_device *phydev)
 {
        int ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL,
@@ -248,6 +175,24 @@ static bool mv2222_is_1gbx_capable(struct phy_device *phydev)
                                 priv->supported);
 }
 
+static bool mv2222_is_sgmii_capable(struct phy_device *phydev)
+{
+       struct mv2222_data *priv = phydev->priv;
+
+       return (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+                                 priv->supported) ||
+               linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+                                 priv->supported) ||
+               linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+                                 priv->supported) ||
+               linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+                                 priv->supported) ||
+               linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+                                 priv->supported) ||
+               linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+                                 priv->supported));
+}
+
 static int mv2222_config_line(struct phy_device *phydev)
 {
        struct mv2222_data *priv = phydev->priv;
@@ -267,7 +212,8 @@ static int mv2222_config_line(struct phy_device *phydev)
        }
 }
 
-static int mv2222_setup_forced(struct phy_device *phydev)
+/* Switch between 1G (1000Base-X/SGMII) and 10G (10GBase-R) modes */
+static int mv2222_swap_line_type(struct phy_device *phydev)
 {
        struct mv2222_data *priv = phydev->priv;
        bool changed = false;
@@ -275,25 +221,23 @@ static int mv2222_setup_forced(struct phy_device *phydev)
 
        switch (priv->line_interface) {
        case PHY_INTERFACE_MODE_10GBASER:
-               if (phydev->speed == SPEED_1000 &&
-                   mv2222_is_1gbx_capable(phydev)) {
+               if (mv2222_is_1gbx_capable(phydev)) {
                        priv->line_interface = PHY_INTERFACE_MODE_1000BASEX;
                        changed = true;
                }
 
-               break;
-       case PHY_INTERFACE_MODE_1000BASEX:
-               if (phydev->speed == SPEED_10000 &&
-                   mv2222_is_10g_capable(phydev)) {
-                       priv->line_interface = PHY_INTERFACE_MODE_10GBASER;
+               if (mv2222_is_sgmii_capable(phydev)) {
+                       priv->line_interface = PHY_INTERFACE_MODE_SGMII;
                        changed = true;
                }
 
                break;
+       case PHY_INTERFACE_MODE_1000BASEX:
        case PHY_INTERFACE_MODE_SGMII:
-               ret = mv2222_set_sgmii_speed(phydev);
-               if (ret < 0)
-                       return ret;
+               if (mv2222_is_10g_capable(phydev)) {
+                       priv->line_interface = PHY_INTERFACE_MODE_10GBASER;
+                       changed = true;
+               }
 
                break;
        default:
@@ -306,6 +250,29 @@ static int mv2222_setup_forced(struct phy_device *phydev)
                        return ret;
        }
 
+       return 0;
+}
+
+static int mv2222_setup_forced(struct phy_device *phydev)
+{
+       struct mv2222_data *priv = phydev->priv;
+       int ret;
+
+       if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER) {
+               if (phydev->speed < SPEED_10000 &&
+                   phydev->speed != SPEED_UNKNOWN) {
+                       ret = mv2222_swap_line_type(phydev);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       if (priv->line_interface == PHY_INTERFACE_MODE_SGMII) {
+               ret = mv2222_set_sgmii_speed(phydev);
+               if (ret < 0)
+                       return ret;
+       }
+
        return mv2222_disable_aneg(phydev);
 }
 
@@ -319,17 +286,9 @@ static int mv2222_config_aneg(struct phy_device *phydev)
                return 0;
 
        if (phydev->autoneg == AUTONEG_DISABLE ||
-           phydev->speed == SPEED_10000)
+           priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
                return mv2222_setup_forced(phydev);
 
-       if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER &&
-           mv2222_is_1gbx_capable(phydev)) {
-               priv->line_interface = PHY_INTERFACE_MODE_1000BASEX;
-               ret = mv2222_config_line(phydev);
-               if (ret < 0)
-                       return ret;
-       }
-
        adv = linkmode_adv_to_mii_adv_x(priv->supported,
                                        ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
 
@@ -363,6 +322,135 @@ static int mv2222_aneg_done(struct phy_device *phydev)
        return (ret & BMSR_ANEGCOMPLETE);
 }
 
+/* Returns negative on error, 0 if link is down, 1 if link is up */
+static int mv2222_read_status_10g(struct phy_device *phydev)
+{
+       static int timeout;
+       int val, link = 0;
+
+       val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
+       if (val < 0)
+               return val;
+
+       if (val & MDIO_STAT1_LSTATUS) {
+               link = 1;
+
+               /* 10GBASE-R do not support auto-negotiation */
+               phydev->autoneg = AUTONEG_DISABLE;
+               phydev->speed = SPEED_10000;
+               phydev->duplex = DUPLEX_FULL;
+       } else {
+               if (phydev->autoneg == AUTONEG_ENABLE) {
+                       timeout++;
+
+                       if (timeout > AUTONEG_TIMEOUT) {
+                               timeout = 0;
+
+                               val = mv2222_swap_line_type(phydev);
+                               if (val < 0)
+                                       return val;
+
+                               return mv2222_config_aneg(phydev);
+                       }
+               }
+       }
+
+       return link;
+}
+
+/* Returns negative on error, 0 if link is down, 1 if link is up */
+static int mv2222_read_status_1g(struct phy_device *phydev)
+{
+       static int timeout;
+       int val, link = 0;
+
+       val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
+       if (val < 0)
+               return val;
+
+       if (phydev->autoneg == AUTONEG_ENABLE &&
+           !(val & BMSR_ANEGCOMPLETE)) {
+               timeout++;
+
+               if (timeout > AUTONEG_TIMEOUT) {
+                       timeout = 0;
+
+                       val = mv2222_swap_line_type(phydev);
+                       if (val < 0)
+                               return val;
+
+                       return mv2222_config_aneg(phydev);
+               }
+
+               return 0;
+       }
+
+       if (!(val & BMSR_LSTATUS))
+               return 0;
+
+       link = 1;
+
+       val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_PHY_STAT);
+       if (val < 0)
+               return val;
+
+       if (val & MV_1GBX_PHY_STAT_AN_RESOLVED) {
+               if (val & MV_1GBX_PHY_STAT_DUPLEX)
+                       phydev->duplex = DUPLEX_FULL;
+               else
+                       phydev->duplex = DUPLEX_HALF;
+
+               if (val & MV_1GBX_PHY_STAT_SPEED1000)
+                       phydev->speed = SPEED_1000;
+               else if (val & MV_1GBX_PHY_STAT_SPEED100)
+                       phydev->speed = SPEED_100;
+               else
+                       phydev->speed = SPEED_10;
+       }
+
+       return link;
+}
+
+static bool mv2222_link_is_operational(struct phy_device *phydev)
+{
+       struct mv2222_data *priv = phydev->priv;
+       int val;
+
+       val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_RX_SIGNAL_DETECT);
+       if (val < 0 || !(val & MV_RX_SIGNAL_DETECT_GLOBAL))
+               return false;
+
+       if (phydev->sfp_bus && !priv->sfp_link)
+               return false;
+
+       return true;
+}
+
+static int mv2222_read_status(struct phy_device *phydev)
+{
+       struct mv2222_data *priv = phydev->priv;
+       int link;
+
+       phydev->link = 0;
+       phydev->speed = SPEED_UNKNOWN;
+       phydev->duplex = DUPLEX_UNKNOWN;
+
+       if (!mv2222_link_is_operational(phydev))
+               return 0;
+
+       if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
+               link = mv2222_read_status_10g(phydev);
+       else
+               link = mv2222_read_status_1g(phydev);
+
+       if (link < 0)
+               return link;
+
+       phydev->link = link;
+
+       return 0;
+}
+
 static int mv2222_resume(struct phy_device *phydev)
 {
        return mv2222_tx_enable(phydev);
@@ -424,11 +512,7 @@ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
                return ret;
 
        if (mutex_trylock(&phydev->lock)) {
-               if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
-                       ret = mv2222_setup_forced(phydev);
-               else
-                       ret = mv2222_config_aneg(phydev);
-
+               ret = mv2222_config_aneg(phydev);
                mutex_unlock(&phydev->lock);
        }
 
@@ -446,9 +530,29 @@ static void mv2222_sfp_remove(void *upstream)
        linkmode_zero(priv->supported);
 }
 
+static void mv2222_sfp_link_up(void *upstream)
+{
+       struct phy_device *phydev = upstream;
+       struct mv2222_data *priv;
+
+       priv = phydev->priv;
+       priv->sfp_link = true;
+}
+
+static void mv2222_sfp_link_down(void *upstream)
+{
+       struct phy_device *phydev = upstream;
+       struct mv2222_data *priv;
+
+       priv = phydev->priv;
+       priv->sfp_link = false;
+}
+
 static const struct sfp_upstream_ops sfp_phy_ops = {
        .module_insert = mv2222_sfp_insert,
        .module_remove = mv2222_sfp_remove,
+       .link_up = mv2222_sfp_link_up,
+       .link_down = mv2222_sfp_link_down,
        .attach = phy_sfp_attach,
        .detach = phy_sfp_detach,
 };
index d66593f..ea00fbb 100644 (file)
@@ -1759,17 +1759,11 @@ err_core_destroy:
        return ret;
 }
 
-static int ath10k_snoc_remove(struct platform_device *pdev)
+static int ath10k_snoc_free_resources(struct ath10k *ar)
 {
-       struct ath10k *ar = platform_get_drvdata(pdev);
        struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 
-       ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n");
-
-       reinit_completion(&ar->driver_recovery);
-
-       if (test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))
-               wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ);
+       ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc free resources\n");
 
        set_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags);
 
@@ -1783,12 +1777,29 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int ath10k_snoc_remove(struct platform_device *pdev)
+{
+       struct ath10k *ar = platform_get_drvdata(pdev);
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+       ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n");
+
+       reinit_completion(&ar->driver_recovery);
+
+       if (test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))
+               wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ);
+
+       ath10k_snoc_free_resources(ar);
+
+       return 0;
+}
+
 static void ath10k_snoc_shutdown(struct platform_device *pdev)
 {
        struct ath10k *ar = platform_get_drvdata(pdev);
 
        ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n");
-       ath10k_snoc_remove(pdev);
+       ath10k_snoc_free_resources(ar);
 }
 
 static struct platform_driver ath10k_snoc_driver = {
index d4ef45c..8c9c781 100644 (file)
@@ -373,7 +373,7 @@ static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
        cfg->tgt_ce = ab->hw_params.target_ce_config;
        cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
        cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
-       ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074;
+       ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
 }
 
 static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
index 987c650..de8b632 100644 (file)
@@ -187,6 +187,59 @@ const struct ce_attr ath11k_host_ce_config_qca6390[] = {
 
 };
 
+const struct ce_attr ath11k_host_ce_config_qcn9074[] = {
+       /* CE0: host->target HTC control and raw streams */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 16,
+               .src_sz_max = 2048,
+               .dest_nentries = 0,
+       },
+
+       /* CE1: target->host HTT + HTC control */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 512,
+               .recv_cb = ath11k_htc_rx_completion_handler,
+       },
+
+       /* CE2: target->host WMI */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 32,
+               .recv_cb = ath11k_htc_rx_completion_handler,
+       },
+
+       /* CE3: host->target WMI (mac0) */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 32,
+               .src_sz_max = 2048,
+               .dest_nentries = 0,
+       },
+
+       /* CE4: host->target HTT */
+       {
+               .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
+               .src_nentries = 2048,
+               .src_sz_max = 256,
+               .dest_nentries = 0,
+       },
+
+       /* CE5: target->host pktlog */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 512,
+               .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler,
+       },
+};
+
 static bool ath11k_ce_need_shadow_fix(int ce_id)
 {
        /* only ce4 needs shadow workaroud*/
@@ -455,7 +508,7 @@ static void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_
                                                 struct hal_srng_params *ring_params)
 {
        u32 msi_data_start;
-       u32 msi_data_count;
+       u32 msi_data_count, msi_data_idx;
        u32 msi_irq_start;
        u32 addr_lo;
        u32 addr_hi;
@@ -469,10 +522,11 @@ static void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_
                return;
 
        ath11k_get_msi_address(ab, &addr_lo, &addr_hi);
+       ath11k_get_ce_msi_idx(ab, ce_id, &msi_data_idx);
 
        ring_params->msi_addr = addr_lo;
        ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32);
-       ring_params->msi_data = (ce_id % msi_data_count) + msi_data_start;
+       ring_params->msi_data = (msi_data_idx % msi_data_count) + msi_data_start;
        ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR;
 }
 
index d6eeef9..713f766 100644 (file)
@@ -173,6 +173,7 @@ struct ath11k_ce {
 
 extern const struct ce_attr ath11k_host_ce_config_ipq8074[];
 extern const struct ce_attr ath11k_host_ce_config_qca6390[];
+extern const struct ce_attr ath11k_host_ce_config_qcn9074[];
 
 void ath11k_ce_cleanup_pipes(struct ath11k_base *ab);
 void ath11k_ce_rx_replenish_retry(struct timer_list *t);
index 350b791..77ce334 100644 (file)
@@ -45,6 +45,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
                .ring_mask = &ath11k_hw_ring_mask_ipq8074,
                .internal_sleep_clock = false,
                .regs = &ipq8074_regs,
+               .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074,
                .host_ce_config = ath11k_host_ce_config_ipq8074,
                .ce_count = 12,
                .target_ce_config = ath11k_target_ce_config_wlan_ipq8074,
@@ -68,6 +69,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
                .idle_ps = false,
                .cold_boot_calib = true,
                .supports_suspend = false,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
        },
        {
                .hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -83,6 +85,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
                .ring_mask = &ath11k_hw_ring_mask_ipq8074,
                .internal_sleep_clock = false,
                .regs = &ipq8074_regs,
+               .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074,
                .host_ce_config = ath11k_host_ce_config_ipq8074,
                .ce_count = 12,
                .target_ce_config = ath11k_target_ce_config_wlan_ipq8074,
@@ -106,6 +109,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
                .idle_ps = false,
                .cold_boot_calib = true,
                .supports_suspend = false,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
        },
        {
                .name = "qca6390 hw2.0",
@@ -121,6 +125,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
                .ring_mask = &ath11k_hw_ring_mask_qca6390,
                .internal_sleep_clock = true,
                .regs = &qca6390_regs,
+               .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390,
                .host_ce_config = ath11k_host_ce_config_qca6390,
                .ce_count = 9,
                .target_ce_config = ath11k_target_ce_config_wlan_qca6390,
@@ -143,6 +148,44 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
                .idle_ps = true,
                .cold_boot_calib = false,
                .supports_suspend = true,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+       },
+       {
+               .name = "qcn9074 hw1.0",
+               .hw_rev = ATH11K_HW_QCN9074_HW10,
+               .fw = {
+                       .dir = "QCN9074/hw1.0",
+                       .board_size = 256 * 1024,
+                       .cal_size = 256 * 1024,
+               },
+               .max_radios = 1,
+               .single_pdev_only = false,
+               .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9074,
+               .hw_ops = &qcn9074_ops,
+               .ring_mask = &ath11k_hw_ring_mask_qcn9074,
+               .internal_sleep_clock = false,
+               .regs = &qcn9074_regs,
+               .host_ce_config = ath11k_host_ce_config_qcn9074,
+               .ce_count = 6,
+               .target_ce_config = ath11k_target_ce_config_wlan_qcn9074,
+               .target_ce_count = 9,
+               .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qcn9074,
+               .svc_to_ce_map_len = 18,
+               .rxdma1_enable = true,
+               .num_rxmda_per_pdev = 1,
+               .rx_mac_buf_ring = false,
+               .vdev_start_delay = false,
+               .htt_peer_map_v2 = true,
+               .tcl_0_only = false,
+               .interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                       BIT(NL80211_IFTYPE_AP) |
+                                       BIT(NL80211_IFTYPE_MESH_POINT),
+               .supports_monitor = true,
+               .supports_shadow_regs = false,
+               .idle_ps = false,
+               .cold_boot_calib = false,
+               .supports_suspend = false,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
        },
 };
 
@@ -974,7 +1017,7 @@ static int ath11k_init_hw_params(struct ath11k_base *ab)
 
        ab->hw_params = *hw_params;
 
-       ath11k_dbg(ab, ATH11K_DBG_BOOT, "Hardware name %s\n", ab->hw_params.name);
+       ath11k_info(ab, "%s\n", ab->hw_params.name);
 
        return 0;
 }
index 8d29845..55af982 100644 (file)
@@ -34,6 +34,7 @@
 #define ATH11K_PRB_RSP_DROP_THRESHOLD ((ATH11K_TX_MGMT_TARGET_MAX_SUPPORT_WMI * 3) / 4)
 
 #define ATH11K_INVALID_HW_MAC_ID       0xFF
+#define ATH11K_CONNECTION_LOSS_HZ      (3 * HZ)
 
 extern unsigned int ath11k_frame_mode;
 
@@ -105,6 +106,7 @@ enum ath11k_hw_rev {
        ATH11K_HW_IPQ8074,
        ATH11K_HW_QCA6390_HW20,
        ATH11K_HW_IPQ6018_HW10,
+       ATH11K_HW_QCN9074_HW10,
 };
 
 enum ath11k_firmware_mode {
@@ -234,6 +236,7 @@ struct ath11k_vif {
        u32 aid;
        u8 bssid[ETH_ALEN];
        struct cfg80211_bitrate_mask bitrate_mask;
+       struct delayed_work connection_loss_work;
        int num_legacy_stations;
        int rtscts_prot_mode;
        int txpower;
@@ -607,6 +610,7 @@ struct ath11k_bus_params {
        bool m3_fw_support;
        bool fixed_bdf_addr;
        bool fixed_mem_region;
+       bool static_window_map;
 };
 
 /* IPQ8074 HW channel counters frequency value in hertz */
@@ -876,6 +880,8 @@ extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq6018
 extern const struct ce_pipe_config ath11k_target_ce_config_wlan_qca6390[];
 extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_qca6390[];
 
+extern const struct ce_pipe_config ath11k_target_ce_config_wlan_qcn9074[];
+extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_qcn9074[];
 int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab);
 int ath11k_core_pre_init(struct ath11k_base *ab);
 int ath11k_core_init(struct ath11k_base *ath11k);
index e136843..ec93f14 100644 (file)
@@ -3851,7 +3851,7 @@ htt_print_pdev_obss_pd_stats_tlv_v(const void *tag_buf,
                           htt_stats_buf->num_non_srg_ppdu_tried);
        len += HTT_DBG_OUT(buf + len, buf_len - len, "Non-SRG success PPDU = %u\n",
                           htt_stats_buf->num_non_srg_ppdu_success);
-       len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG Opportunies = %u\n",
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG Opportunities = %u\n",
                           htt_stats_buf->num_srg_opportunities);
        len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG tried PPDU = %u\n",
                           htt_stats_buf->num_srg_ppdu_tried);
index 850ad38..1d9aa1b 100644 (file)
 
 #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ)
 
-static u8 *ath11k_dp_rx_h_80211_hdr(struct hal_rx_desc *desc)
+static u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc)
 {
-       return desc->hdr_status;
+       return ab->hw_params.hw_ops->rx_desc_get_hdr_status(desc);
 }
 
-static enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct hal_rx_desc *desc)
+static enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_base *ab,
+                                                              struct hal_rx_desc *desc)
 {
-       if (!(__le32_to_cpu(desc->mpdu_start.info1) &
-           RX_MPDU_START_INFO1_ENCRYPT_INFO_VALID))
+       if (!ab->hw_params.hw_ops->rx_desc_encrypt_valid(desc))
                return HAL_ENCRYPT_TYPE_OPEN;
 
-       return FIELD_GET(RX_MPDU_START_INFO2_ENC_TYPE,
-                        __le32_to_cpu(desc->mpdu_start.info2));
+       return ab->hw_params.hw_ops->rx_desc_get_encrypt_type(desc);
 }
 
-static u8 ath11k_dp_rx_h_msdu_start_decap_type(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_msdu_start_decap_type(struct ath11k_base *ab,
+                                              struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT,
-                        __le32_to_cpu(desc->msdu_start.info2));
+       return ab->hw_params.hw_ops->rx_desc_get_decap_type(desc);
 }
 
-static u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab,
+                                                    struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MSDU_START_INFO2_MESH_CTRL_PRESENT,
-                        __le32_to_cpu(desc->msdu_start.info2));
+       return ab->hw_params.hw_ops->rx_desc_get_mesh_ctl(desc);
 }
 
-static bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct hal_rx_desc *desc)
+static bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct ath11k_base *ab,
+                                                    struct hal_rx_desc *desc)
 {
-       return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID,
-                          __le32_to_cpu(desc->mpdu_start.info1));
+       return ab->hw_params.hw_ops->rx_desc_get_mpdu_seq_ctl_vld(desc);
 }
 
-static bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct hal_rx_desc *desc)
+static bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct ath11k_base *ab,
+                                              struct hal_rx_desc *desc)
 {
-       return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_FCTRL_VALID,
-                          __le32_to_cpu(desc->mpdu_start.info1));
+       return ab->hw_params.hw_ops->rx_desc_get_mpdu_fc_valid(desc);
 }
 
-static bool ath11k_dp_rx_h_mpdu_start_more_frags(struct sk_buff *skb)
+static bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab,
+                                                struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
 
-       hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE);
+       hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params.hal_desc_sz);
        return ieee80211_has_morefrags(hdr->frame_control);
 }
 
-static u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct sk_buff *skb)
+static u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab,
+                                            struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
 
-       hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE);
+       hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params.hal_desc_sz);
        return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
 }
 
-static u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct hal_rx_desc *desc)
+static u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct ath11k_base *ab,
+                                           struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_NUM,
-                        __le32_to_cpu(desc->mpdu_start.info1));
+       return ab->hw_params.hw_ops->rx_desc_get_mpdu_start_seq_no(desc);
 }
 
-static bool ath11k_dp_rx_h_attn_msdu_done(struct hal_rx_desc *desc)
+static void *ath11k_dp_rx_get_attention(struct ath11k_base *ab,
+                                       struct hal_rx_desc *desc)
+{
+       return ab->hw_params.hw_ops->rx_desc_get_attention(desc);
+}
+
+static bool ath11k_dp_rx_h_attn_msdu_done(struct rx_attention *attn)
 {
        return !!FIELD_GET(RX_ATTENTION_INFO2_MSDU_DONE,
-                          __le32_to_cpu(desc->attention.info2));
+                          __le32_to_cpu(attn->info2));
 }
 
-static bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct hal_rx_desc *desc)
+static bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct rx_attention *attn)
 {
        return !!FIELD_GET(RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL,
-                          __le32_to_cpu(desc->attention.info1));
+                          __le32_to_cpu(attn->info1));
 }
 
-static bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct hal_rx_desc *desc)
+static bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct rx_attention *attn)
 {
        return !!FIELD_GET(RX_ATTENTION_INFO1_IP_CKSUM_FAIL,
-                          __le32_to_cpu(desc->attention.info1));
+                          __le32_to_cpu(attn->info1));
 }
 
-static bool ath11k_dp_rx_h_attn_is_decrypted(struct hal_rx_desc *desc)
+static bool ath11k_dp_rx_h_attn_is_decrypted(struct rx_attention *attn)
 {
        return (FIELD_GET(RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE,
-                         __le32_to_cpu(desc->attention.info2)) ==
+                         __le32_to_cpu(attn->info2)) ==
                RX_DESC_DECRYPT_STATUS_CODE_OK);
 }
 
-static u32 ath11k_dp_rx_h_attn_mpdu_err(struct hal_rx_desc *desc)
+static u32 ath11k_dp_rx_h_attn_mpdu_err(struct rx_attention *attn)
 {
-       u32 info = __le32_to_cpu(desc->attention.info1);
+       u32 info = __le32_to_cpu(attn->info1);
        u32 errmap = 0;
 
        if (info & RX_ATTENTION_INFO1_FCS_ERR)
@@ -135,131 +142,122 @@ static u32 ath11k_dp_rx_h_attn_mpdu_err(struct hal_rx_desc *desc)
        return errmap;
 }
 
-static u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct hal_rx_desc *desc)
+static u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab,
+                                             struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MSDU_START_INFO1_MSDU_LENGTH,
-                        __le32_to_cpu(desc->msdu_start.info1));
+       return ab->hw_params.hw_ops->rx_desc_get_msdu_len(desc);
 }
 
-static u8 ath11k_dp_rx_h_msdu_start_sgi(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_msdu_start_sgi(struct ath11k_base *ab,
+                                       struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MSDU_START_INFO3_SGI,
-                        __le32_to_cpu(desc->msdu_start.info3));
+       return ab->hw_params.hw_ops->rx_desc_get_msdu_sgi(desc);
 }
 
-static u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct ath11k_base *ab,
+                                            struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MSDU_START_INFO3_RATE_MCS,
-                        __le32_to_cpu(desc->msdu_start.info3));
+       return ab->hw_params.hw_ops->rx_desc_get_msdu_rate_mcs(desc);
 }
 
-static u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct ath11k_base *ab,
+                                         struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MSDU_START_INFO3_RECV_BW,
-                        __le32_to_cpu(desc->msdu_start.info3));
+       return ab->hw_params.hw_ops->rx_desc_get_msdu_rx_bw(desc);
 }
 
-static u32 ath11k_dp_rx_h_msdu_start_freq(struct hal_rx_desc *desc)
+static u32 ath11k_dp_rx_h_msdu_start_freq(struct ath11k_base *ab,
+                                         struct hal_rx_desc *desc)
 {
-       return __le32_to_cpu(desc->msdu_start.phy_meta_data);
+       return ab->hw_params.hw_ops->rx_desc_get_msdu_freq(desc);
 }
 
-static u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct ath11k_base *ab,
+                                            struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MSDU_START_INFO3_PKT_TYPE,
-                        __le32_to_cpu(desc->msdu_start.info3));
+       return ab->hw_params.hw_ops->rx_desc_get_msdu_pkt_type(desc);
 }
 
-static u8 ath11k_dp_rx_h_msdu_start_nss(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_msdu_start_nss(struct ath11k_base *ab,
+                                       struct hal_rx_desc *desc)
 {
-       u8 mimo_ss_bitmap = FIELD_GET(RX_MSDU_START_INFO3_MIMO_SS_BITMAP,
-                                     __le32_to_cpu(desc->msdu_start.info3));
-
-       return hweight8(mimo_ss_bitmap);
+       return hweight8(ab->hw_params.hw_ops->rx_desc_get_msdu_nss(desc));
 }
 
-static u8 ath11k_dp_rx_h_mpdu_start_tid(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_mpdu_start_tid(struct ath11k_base *ab,
+                                       struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MPDU_START_INFO2_TID,
-                        __le32_to_cpu(desc->mpdu_start.info2));
+       return ab->hw_params.hw_ops->rx_desc_get_mpdu_tid(desc);
 }
 
-static u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct hal_rx_desc *desc)
+static u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab,
+                                            struct hal_rx_desc *desc)
 {
-       return __le16_to_cpu(desc->mpdu_start.sw_peer_id);
+       return ab->hw_params.hw_ops->rx_desc_get_mpdu_peer_id(desc);
 }
 
-static u8 ath11k_dp_rx_h_msdu_end_l3pad(struct hal_rx_desc *desc)
+static u8 ath11k_dp_rx_h_msdu_end_l3pad(struct ath11k_base *ab,
+                                       struct hal_rx_desc *desc)
 {
-       return FIELD_GET(RX_MSDU_END_INFO2_L3_HDR_PADDING,
-                        __le32_to_cpu(desc->msdu_end.info2));
+       return ab->hw_params.hw_ops->rx_desc_get_l3_pad_bytes(desc);
 }
 
-static bool ath11k_dp_rx_h_msdu_end_first_msdu(struct hal_rx_desc *desc)
+static bool ath11k_dp_rx_h_msdu_end_first_msdu(struct ath11k_base *ab,
+                                              struct hal_rx_desc *desc)
 {
-       return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU,
-                          __le32_to_cpu(desc->msdu_end.info2));
+       return ab->hw_params.hw_ops->rx_desc_get_first_msdu(desc);
 }
 
-static bool ath11k_dp_rx_h_msdu_end_last_msdu(struct hal_rx_desc *desc)
+static bool ath11k_dp_rx_h_msdu_end_last_msdu(struct ath11k_base *ab,
+                                             struct hal_rx_desc *desc)
 {
-       return !!FIELD_GET(RX_MSDU_END_INFO2_LAST_MSDU,
-                          __le32_to_cpu(desc->msdu_end.info2));
+       return ab->hw_params.hw_ops->rx_desc_get_last_msdu(desc);
 }
 
-static void ath11k_dp_rx_desc_end_tlv_copy(struct hal_rx_desc *fdesc,
+static void ath11k_dp_rx_desc_end_tlv_copy(struct ath11k_base *ab,
+                                          struct hal_rx_desc *fdesc,
                                           struct hal_rx_desc *ldesc)
 {
-       memcpy((u8 *)&fdesc->msdu_end, (u8 *)&ldesc->msdu_end,
-              sizeof(struct rx_msdu_end));
-       memcpy((u8 *)&fdesc->attention, (u8 *)&ldesc->attention,
-              sizeof(struct rx_attention));
-       memcpy((u8 *)&fdesc->mpdu_end, (u8 *)&ldesc->mpdu_end,
-              sizeof(struct rx_mpdu_end));
+       ab->hw_params.hw_ops->rx_desc_copy_attn_end_tlv(fdesc, ldesc);
 }
 
-static u32 ath11k_dp_rxdesc_get_mpdulen_err(struct hal_rx_desc *rx_desc)
+static u32 ath11k_dp_rxdesc_get_mpdulen_err(struct rx_attention *attn)
 {
-       struct rx_attention *rx_attn;
-
-       rx_attn = &rx_desc->attention;
-
        return FIELD_GET(RX_ATTENTION_INFO1_MPDU_LEN_ERR,
-                        __le32_to_cpu(rx_attn->info1));
+                        __le32_to_cpu(attn->info1));
 }
 
-static u32 ath11k_dp_rxdesc_get_decap_format(struct hal_rx_desc *rx_desc)
-{
-       struct rx_msdu_start *rx_msdu_start;
-
-       rx_msdu_start = &rx_desc->msdu_start;
-
-       return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT,
-                        __le32_to_cpu(rx_msdu_start->info2));
-}
-
-static u8 *ath11k_dp_rxdesc_get_80211hdr(struct hal_rx_desc *rx_desc)
+static u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab,
+                                        struct hal_rx_desc *rx_desc)
 {
        u8 *rx_pkt_hdr;
 
-       rx_pkt_hdr = &rx_desc->msdu_payload[0];
+       rx_pkt_hdr = ab->hw_params.hw_ops->rx_desc_get_msdu_payload(rx_desc);
 
        return rx_pkt_hdr;
 }
 
-static bool ath11k_dp_rxdesc_mpdu_valid(struct hal_rx_desc *rx_desc)
+static bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab,
+                                       struct hal_rx_desc *rx_desc)
 {
        u32 tlv_tag;
 
-       tlv_tag = FIELD_GET(HAL_TLV_HDR_TAG,
-                           __le32_to_cpu(rx_desc->mpdu_start_tag));
+       tlv_tag = ab->hw_params.hw_ops->rx_desc_get_mpdu_start_tag(rx_desc);
 
        return tlv_tag == HAL_RX_MPDU_START;
 }
 
-static u32 ath11k_dp_rxdesc_get_ppduid(struct hal_rx_desc *rx_desc)
+static u32 ath11k_dp_rxdesc_get_ppduid(struct ath11k_base *ab,
+                                      struct hal_rx_desc *rx_desc)
+{
+       return ab->hw_params.hw_ops->rx_desc_get_mpdu_ppdu_id(rx_desc);
+}
+
+static void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab,
+                                         struct hal_rx_desc *desc,
+                                         u16 len)
 {
-       return __le16_to_cpu(rx_desc->mpdu_start.phy_ppdu_id);
+       ab->hw_params.hw_ops->rx_desc_set_msdu_len(desc, len);
 }
 
 static void ath11k_dp_service_mon_ring(struct timer_list *t)
@@ -1722,19 +1720,19 @@ static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
                                      struct sk_buff *first, struct sk_buff *last,
                                      u8 l3pad_bytes, int msdu_len)
 {
+       struct ath11k_base *ab = ar->ab;
        struct sk_buff *skb;
        struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first);
        int buf_first_hdr_len, buf_first_len;
        struct hal_rx_desc *ldesc;
-       int space_extra;
-       int rem_len;
-       int buf_len;
+       int space_extra, rem_len, buf_len;
+       u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
 
        /* As the msdu is spread across multiple rx buffers,
         * find the offset to the start of msdu for computing
         * the length of the msdu in the first buffer.
         */
-       buf_first_hdr_len = HAL_RX_DESC_SIZE + l3pad_bytes;
+       buf_first_hdr_len = hal_rx_desc_sz + l3pad_bytes;
        buf_first_len = DP_RX_BUFFER_SIZE - buf_first_hdr_len;
 
        if (WARN_ON_ONCE(msdu_len <= buf_first_len)) {
@@ -1744,8 +1742,8 @@ static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
        }
 
        ldesc = (struct hal_rx_desc *)last->data;
-       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ldesc);
-       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ldesc);
+       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ab, ldesc);
+       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ab, ldesc);
 
        /* MSDU spans over multiple buffers because the length of the MSDU
         * exceeds DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. So assume the data
@@ -1757,7 +1755,7 @@ static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
        /* When an MSDU spread over multiple buffers attention, MSDU_END and
         * MPDU_END tlvs are valid only in the last buffer. Copy those tlvs.
         */
-       ath11k_dp_rx_desc_end_tlv_copy(rxcb->rx_desc, ldesc);
+       ath11k_dp_rx_desc_end_tlv_copy(ab, rxcb->rx_desc, ldesc);
 
        space_extra = msdu_len - (buf_first_len + skb_tailroom(first));
        if (space_extra > 0 &&
@@ -1778,18 +1776,18 @@ static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
        while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) {
                rxcb = ATH11K_SKB_RXCB(skb);
                if (rxcb->is_continuation)
-                       buf_len = DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE;
+                       buf_len = DP_RX_BUFFER_SIZE - hal_rx_desc_sz;
                else
                        buf_len = rem_len;
 
-               if (buf_len > (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE)) {
+               if (buf_len > (DP_RX_BUFFER_SIZE - hal_rx_desc_sz)) {
                        WARN_ON_ONCE(1);
                        dev_kfree_skb_any(skb);
                        return -EINVAL;
                }
 
-               skb_put(skb, buf_len + HAL_RX_DESC_SIZE);
-               skb_pull(skb, HAL_RX_DESC_SIZE);
+               skb_put(skb, buf_len + hal_rx_desc_sz);
+               skb_pull(skb, hal_rx_desc_sz);
                skb_copy_from_linear_data(skb, skb_put(first, buf_len),
                                          buf_len);
                dev_kfree_skb_any(skb);
@@ -1820,13 +1818,15 @@ static struct sk_buff *ath11k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_
        return NULL;
 }
 
-static void ath11k_dp_rx_h_csum_offload(struct sk_buff *msdu)
+static void ath11k_dp_rx_h_csum_offload(struct ath11k *ar, struct sk_buff *msdu)
 {
        struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       struct rx_attention *rx_attention;
        bool ip_csum_fail, l4_csum_fail;
 
-       ip_csum_fail = ath11k_dp_rx_h_attn_ip_cksum_fail(rxcb->rx_desc);
-       l4_csum_fail = ath11k_dp_rx_h_attn_l4_cksum_fail(rxcb->rx_desc);
+       rx_attention = ath11k_dp_rx_get_attention(ar->ab, rxcb->rx_desc);
+       ip_csum_fail = ath11k_dp_rx_h_attn_ip_cksum_fail(rx_attention);
+       l4_csum_fail = ath11k_dp_rx_h_attn_l4_cksum_fail(rx_attention);
 
        msdu->ip_summed = (ip_csum_fail || l4_csum_fail) ?
                          CHECKSUM_NONE : CHECKSUM_UNNECESSARY;
@@ -1957,7 +1957,7 @@ static void ath11k_dp_rx_h_undecap_nwifi(struct ath11k *ar,
 
                qos_ctl = rxcb->tid;
 
-               if (ath11k_dp_rx_h_msdu_start_mesh_ctl_present(rxcb->rx_desc))
+               if (ath11k_dp_rx_h_msdu_start_mesh_ctl_present(ar->ab, rxcb->rx_desc))
                        qos_ctl |= IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT;
 
                /* TODO Add other QoS ctl fields when required */
@@ -2061,7 +2061,7 @@ static void *ath11k_dp_rx_h_find_rfc1042(struct ath11k *ar,
        bool is_amsdu;
 
        is_amsdu = !(rxcb->is_first_msdu && rxcb->is_last_msdu);
-       hdr = (struct ieee80211_hdr *)ath11k_dp_rx_h_80211_hdr(rxcb->rx_desc);
+       hdr = (struct ieee80211_hdr *)ath11k_dp_rx_h_80211_hdr(ar->ab, rxcb->rx_desc);
        rfc1042 = hdr;
 
        if (rxcb->is_first_msdu) {
@@ -2134,8 +2134,8 @@ static void ath11k_dp_rx_h_undecap(struct ath11k *ar, struct sk_buff *msdu,
        u8 *first_hdr;
        u8 decap;
 
-       first_hdr = ath11k_dp_rx_h_80211_hdr(rx_desc);
-       decap = ath11k_dp_rx_h_msdu_start_decap_type(rx_desc);
+       first_hdr = ath11k_dp_rx_h_80211_hdr(ar->ab, rx_desc);
+       decap = ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rx_desc);
 
        switch (decap) {
        case DP_RX_DECAP_TYPE_NATIVE_WIFI:
@@ -2167,6 +2167,7 @@ static void ath11k_dp_rx_h_mpdu(struct ath11k *ar,
        bool is_decrypted = false;
        struct ieee80211_hdr *hdr;
        struct ath11k_peer *peer;
+       struct rx_attention *rx_attention;
        u32 err_bitmap;
 
        hdr = (struct ieee80211_hdr *)msdu->data;
@@ -2188,9 +2189,10 @@ static void ath11k_dp_rx_h_mpdu(struct ath11k *ar,
        }
        spin_unlock_bh(&ar->ab->base_lock);
 
-       err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_desc);
+       rx_attention = ath11k_dp_rx_get_attention(ar->ab, rx_desc);
+       err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention);
        if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap)
-               is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_desc);
+               is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_attention);
 
        /* Clear per-MPDU flags while leaving per-PPDU flags intact */
        rx_status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |
@@ -2215,7 +2217,7 @@ static void ath11k_dp_rx_h_mpdu(struct ath11k *ar,
                                           RX_FLAG_PN_VALIDATED;
        }
 
-       ath11k_dp_rx_h_csum_offload(msdu);
+       ath11k_dp_rx_h_csum_offload(ar, msdu);
        ath11k_dp_rx_h_undecap(ar, msdu, rx_desc,
                               enctype, rx_status, is_decrypted);
 
@@ -2236,11 +2238,11 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
        u8 sgi;
        bool is_cck;
 
-       pkt_type = ath11k_dp_rx_h_msdu_start_pkt_type(rx_desc);
-       bw = ath11k_dp_rx_h_msdu_start_rx_bw(rx_desc);
-       rate_mcs = ath11k_dp_rx_h_msdu_start_rate_mcs(rx_desc);
-       nss = ath11k_dp_rx_h_msdu_start_nss(rx_desc);
-       sgi = ath11k_dp_rx_h_msdu_start_sgi(rx_desc);
+       pkt_type = ath11k_dp_rx_h_msdu_start_pkt_type(ar->ab, rx_desc);
+       bw = ath11k_dp_rx_h_msdu_start_rx_bw(ar->ab, rx_desc);
+       rate_mcs = ath11k_dp_rx_h_msdu_start_rate_mcs(ar->ab, rx_desc);
+       nss = ath11k_dp_rx_h_msdu_start_nss(ar->ab, rx_desc);
+       sgi = ath11k_dp_rx_h_msdu_start_sgi(ar->ab, rx_desc);
 
        switch (pkt_type) {
        case RX_MSDU_START_PKT_TYPE_11A:
@@ -2297,7 +2299,7 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
                                struct ieee80211_rx_status *rx_status)
 {
        u8 channel_num;
-       u32 center_freq;
+       u32 center_freq, meta_data;
        struct ieee80211_channel *channel;
 
        rx_status->freq = 0;
@@ -2308,8 +2310,9 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
 
        rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
 
-       channel_num = ath11k_dp_rx_h_msdu_start_freq(rx_desc);
-       center_freq = ath11k_dp_rx_h_msdu_start_freq(rx_desc) >> 16;
+       meta_data = ath11k_dp_rx_h_msdu_start_freq(ar->ab, rx_desc);
+       channel_num = meta_data;
+       center_freq = meta_data >> 16;
 
        if (center_freq >= 5935 && center_freq <= 7105) {
                rx_status->band = NL80211_BAND_6GHZ;
@@ -2409,7 +2412,9 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
                                     struct sk_buff *msdu,
                                     struct sk_buff_head *msdu_list)
 {
+       struct ath11k_base *ab = ar->ab;
        struct hal_rx_desc *rx_desc, *lrx_desc;
+       struct rx_attention *rx_attention;
        struct ieee80211_rx_status rx_status = {0};
        struct ieee80211_rx_status *status;
        struct ath11k_skb_rxcb *rxcb;
@@ -2419,10 +2424,11 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
        u8 *hdr_status;
        u16 msdu_len;
        int ret;
+       u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
 
        last_buf = ath11k_dp_rx_get_msdu_last_buf(msdu_list, msdu);
        if (!last_buf) {
-               ath11k_warn(ar->ab,
+               ath11k_warn(ab,
                            "No valid Rx buffer to access Atten/MSDU_END/MPDU_END tlvs\n");
                ret = -EIO;
                goto free_out;
@@ -2430,38 +2436,39 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
 
        rx_desc = (struct hal_rx_desc *)msdu->data;
        lrx_desc = (struct hal_rx_desc *)last_buf->data;
-       if (!ath11k_dp_rx_h_attn_msdu_done(lrx_desc)) {
-               ath11k_warn(ar->ab, "msdu_done bit in attention is not set\n");
+       rx_attention = ath11k_dp_rx_get_attention(ab, lrx_desc);
+       if (!ath11k_dp_rx_h_attn_msdu_done(rx_attention)) {
+               ath11k_warn(ab, "msdu_done bit in attention is not set\n");
                ret = -EIO;
                goto free_out;
        }
 
        rxcb = ATH11K_SKB_RXCB(msdu);
        rxcb->rx_desc = rx_desc;
-       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc);
-       l3_pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(lrx_desc);
+       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ab, rx_desc);
+       l3_pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ab, lrx_desc);
 
        if (rxcb->is_frag) {
-               skb_pull(msdu, HAL_RX_DESC_SIZE);
+               skb_pull(msdu, hal_rx_desc_sz);
        } else if (!rxcb->is_continuation) {
-               if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) {
-                       hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc);
+               if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) {
+                       hdr_status = ath11k_dp_rx_h_80211_hdr(ab, rx_desc);
                        ret = -EINVAL;
-                       ath11k_warn(ar->ab, "invalid msdu len %u\n", msdu_len);
-                       ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status,
+                       ath11k_warn(ab, "invalid msdu len %u\n", msdu_len);
+                       ath11k_dbg_dump(ab, ATH11K_DBG_DATA, NULL, "", hdr_status,
                                        sizeof(struct ieee80211_hdr));
-                       ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", rx_desc,
+                       ath11k_dbg_dump(ab, ATH11K_DBG_DATA, NULL, "", rx_desc,
                                        sizeof(struct hal_rx_desc));
                        goto free_out;
                }
-               skb_put(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes + msdu_len);
-               skb_pull(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes);
+               skb_put(msdu, hal_rx_desc_sz + l3_pad_bytes + msdu_len);
+               skb_pull(msdu, hal_rx_desc_sz + l3_pad_bytes);
        } else {
                ret = ath11k_dp_rx_msdu_coalesce(ar, msdu_list,
                                                 msdu, last_buf,
                                                 l3_pad_bytes, msdu_len);
                if (ret) {
-                       ath11k_warn(ar->ab,
+                       ath11k_warn(ab,
                                    "failed to coalesce msdu rx buffer%d\n", ret);
                        goto free_out;
                }
@@ -3090,16 +3097,17 @@ static int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer
        u8 mic[IEEE80211_CCMP_MIC_LEN];
        int head_len, tail_len, ret;
        size_t data_len;
-       u32 hdr_len;
+       u32 hdr_len, hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
        u8 *key, *data;
        u8 key_idx;
 
-       if (ath11k_dp_rx_h_mpdu_start_enctype(rx_desc) != HAL_ENCRYPT_TYPE_TKIP_MIC)
+       if (ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, rx_desc) !=
+           HAL_ENCRYPT_TYPE_TKIP_MIC)
                return 0;
 
-       hdr = (struct ieee80211_hdr *)(msdu->data + HAL_RX_DESC_SIZE);
+       hdr = (struct ieee80211_hdr *)(msdu->data + hal_rx_desc_sz);
        hdr_len = ieee80211_hdrlen(hdr->frame_control);
-       head_len = hdr_len + HAL_RX_DESC_SIZE + IEEE80211_TKIP_IV_LEN;
+       head_len = hdr_len + hal_rx_desc_sz + IEEE80211_TKIP_IV_LEN;
        tail_len = IEEE80211_CCMP_MIC_LEN + IEEE80211_TKIP_ICV_LEN + FCS_LEN;
 
        if (!is_multicast_ether_addr(hdr->addr1))
@@ -3125,7 +3133,7 @@ mic_fail:
 
        rxs->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_MMIC_STRIPPED |
                    RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
-       skb_pull(msdu, HAL_RX_DESC_SIZE);
+       skb_pull(msdu, hal_rx_desc_sz);
 
        ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs);
        ath11k_dp_rx_h_undecap(ar, msdu, rx_desc,
@@ -3140,11 +3148,12 @@ static void ath11k_dp_rx_h_undecap_frag(struct ath11k *ar, struct sk_buff *msdu,
        struct ieee80211_hdr *hdr;
        size_t hdr_len;
        size_t crypto_len;
+       u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
 
        if (!flags)
                return;
 
-       hdr = (struct ieee80211_hdr *)(msdu->data + HAL_RX_DESC_SIZE);
+       hdr = (struct ieee80211_hdr *)(msdu->data + hal_rx_desc_sz);
 
        if (flags & RX_FLAG_MIC_STRIPPED)
                skb_trim(msdu, msdu->len -
@@ -3158,8 +3167,8 @@ static void ath11k_dp_rx_h_undecap_frag(struct ath11k *ar, struct sk_buff *msdu,
                hdr_len = ieee80211_hdrlen(hdr->frame_control);
                crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype);
 
-               memmove((void *)msdu->data + HAL_RX_DESC_SIZE + crypto_len,
-                       (void *)msdu->data + HAL_RX_DESC_SIZE, hdr_len);
+               memmove((void *)msdu->data + hal_rx_desc_sz + crypto_len,
+                       (void *)msdu->data + hal_rx_desc_sz, hdr_len);
                skb_pull(msdu, crypto_len);
        }
 }
@@ -3172,11 +3181,12 @@ static int ath11k_dp_rx_h_defrag(struct ath11k *ar,
        struct hal_rx_desc *rx_desc;
        struct sk_buff *skb, *first_frag, *last_frag;
        struct ieee80211_hdr *hdr;
+       struct rx_attention *rx_attention;
        enum hal_encrypt_type enctype;
        bool is_decrypted = false;
        int msdu_len = 0;
        int extra_space;
-       u32 flags;
+       u32 flags, hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
 
        first_frag = skb_peek(&rx_tid->rx_frags);
        last_frag = skb_peek_tail(&rx_tid->rx_frags);
@@ -3184,11 +3194,13 @@ static int ath11k_dp_rx_h_defrag(struct ath11k *ar,
        skb_queue_walk(&rx_tid->rx_frags, skb) {
                flags = 0;
                rx_desc = (struct hal_rx_desc *)skb->data;
-               hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE);
+               hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz);
 
-               enctype = ath11k_dp_rx_h_mpdu_start_enctype(rx_desc);
-               if (enctype != HAL_ENCRYPT_TYPE_OPEN)
-                       is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_desc);
+               enctype = ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, rx_desc);
+               if (enctype != HAL_ENCRYPT_TYPE_OPEN) {
+                       rx_attention = ath11k_dp_rx_get_attention(ar->ab, rx_desc);
+                       is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_attention);
+               }
 
                if (is_decrypted) {
                        if (skb != first_frag)
@@ -3204,7 +3216,7 @@ static int ath11k_dp_rx_h_defrag(struct ath11k *ar,
                ath11k_dp_rx_h_undecap_frag(ar, skb, enctype, flags);
 
                if (skb != first_frag)
-                       skb_pull(skb, HAL_RX_DESC_SIZE +
+                       skb_pull(skb, hal_rx_desc_sz +
                                      ieee80211_hdrlen(hdr->frame_control));
                msdu_len += skb->len;
        }
@@ -3220,7 +3232,7 @@ static int ath11k_dp_rx_h_defrag(struct ath11k *ar,
                dev_kfree_skb_any(skb);
        }
 
-       hdr = (struct ieee80211_hdr *)(first_frag->data + HAL_RX_DESC_SIZE);
+       hdr = (struct ieee80211_hdr *)(first_frag->data + hal_rx_desc_sz);
        hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
        ATH11K_SKB_RXCB(first_frag)->is_frag = 1;
 
@@ -3246,10 +3258,10 @@ static int ath11k_dp_rx_h_defrag_reo_reinject(struct ath11k *ar, struct dp_rx_ti
        struct hal_srng *srng;
        dma_addr_t paddr;
        u32 desc_bank, msdu_info, mpdu_info;
-       u32 dst_idx, cookie;
-       u32 *msdu_len_offset;
+       u32 dst_idx, cookie, hal_rx_desc_sz;
        int ret, buf_id;
 
+       hal_rx_desc_sz = ab->hw_params.hal_desc_sz;
        link_desc_banks = ab->dp.link_desc_banks;
        reo_dest_ring = rx_tid->dst_ring_desc;
 
@@ -3264,16 +3276,14 @@ static int ath11k_dp_rx_h_defrag_reo_reinject(struct ath11k *ar, struct dp_rx_ti
                    FIELD_PREP(RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU, 1) |
                    FIELD_PREP(RX_MSDU_DESC_INFO0_MSDU_CONTINUATION, 0) |
                    FIELD_PREP(RX_MSDU_DESC_INFO0_MSDU_LENGTH,
-                              defrag_skb->len - HAL_RX_DESC_SIZE) |
+                              defrag_skb->len - hal_rx_desc_sz) |
                    FIELD_PREP(RX_MSDU_DESC_INFO0_REO_DEST_IND, dst_idx) |
                    FIELD_PREP(RX_MSDU_DESC_INFO0_VALID_SA, 1) |
                    FIELD_PREP(RX_MSDU_DESC_INFO0_VALID_DA, 1);
        msdu0->rx_msdu_info.info0 = msdu_info;
 
        /* change msdu len in hal rx desc */
-       msdu_len_offset = (u32 *)&rx_desc->msdu_start;
-       *msdu_len_offset &= ~(RX_MSDU_START_INFO1_MSDU_LENGTH);
-       *msdu_len_offset |= defrag_skb->len - HAL_RX_DESC_SIZE;
+       ath11k_dp_rxdesc_set_msdu_len(ab, rx_desc, defrag_skb->len - hal_rx_desc_sz);
 
        paddr = dma_map_single(ab->dev, defrag_skb->data,
                               defrag_skb->len + skb_tailroom(defrag_skb),
@@ -3346,24 +3356,26 @@ err_unmap_dma:
        return ret;
 }
 
-static int ath11k_dp_rx_h_cmp_frags(struct sk_buff *a, struct sk_buff *b)
+static int ath11k_dp_rx_h_cmp_frags(struct ath11k *ar,
+                                   struct sk_buff *a, struct sk_buff *b)
 {
        int frag1, frag2;
 
-       frag1 = ath11k_dp_rx_h_mpdu_start_frag_no(a);
-       frag2 = ath11k_dp_rx_h_mpdu_start_frag_no(b);
+       frag1 = ath11k_dp_rx_h_mpdu_start_frag_no(ar->ab, a);
+       frag2 = ath11k_dp_rx_h_mpdu_start_frag_no(ar->ab, b);
 
        return frag1 - frag2;
 }
 
-static void ath11k_dp_rx_h_sort_frags(struct sk_buff_head *frag_list,
+static void ath11k_dp_rx_h_sort_frags(struct ath11k *ar,
+                                     struct sk_buff_head *frag_list,
                                      struct sk_buff *cur_frag)
 {
        struct sk_buff *skb;
        int cmp;
 
        skb_queue_walk(frag_list, skb) {
-               cmp = ath11k_dp_rx_h_cmp_frags(skb, cur_frag);
+               cmp = ath11k_dp_rx_h_cmp_frags(ar, skb, cur_frag);
                if (cmp < 0)
                        continue;
                __skb_queue_before(frag_list, skb, cur_frag);
@@ -3372,14 +3384,15 @@ static void ath11k_dp_rx_h_sort_frags(struct sk_buff_head *frag_list,
        __skb_queue_tail(frag_list, cur_frag);
 }
 
-static u64 ath11k_dp_rx_h_get_pn(struct sk_buff *skb)
+static u64 ath11k_dp_rx_h_get_pn(struct ath11k *ar, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
        u64 pn = 0;
        u8 *ehdr;
+       u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
 
-       hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE);
-       ehdr = skb->data + HAL_RX_DESC_SIZE + ieee80211_hdrlen(hdr->frame_control);
+       hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz);
+       ehdr = skb->data + hal_rx_desc_sz + ieee80211_hdrlen(hdr->frame_control);
 
        pn = ehdr[0];
        pn |= (u64)ehdr[1] << 8;
@@ -3403,19 +3416,19 @@ ath11k_dp_rx_h_defrag_validate_incr_pn(struct ath11k *ar, struct dp_rx_tid *rx_t
        first_frag = skb_peek(&rx_tid->rx_frags);
        desc = (struct hal_rx_desc *)first_frag->data;
 
-       encrypt_type = ath11k_dp_rx_h_mpdu_start_enctype(desc);
+       encrypt_type = ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, desc);
        if (encrypt_type != HAL_ENCRYPT_TYPE_CCMP_128 &&
            encrypt_type != HAL_ENCRYPT_TYPE_CCMP_256 &&
            encrypt_type != HAL_ENCRYPT_TYPE_GCMP_128 &&
            encrypt_type != HAL_ENCRYPT_TYPE_AES_GCMP_256)
                return true;
 
-       last_pn = ath11k_dp_rx_h_get_pn(first_frag);
+       last_pn = ath11k_dp_rx_h_get_pn(ar, first_frag);
        skb_queue_walk(&rx_tid->rx_frags, skb) {
                if (skb == first_frag)
                        continue;
 
-               cur_pn = ath11k_dp_rx_h_get_pn(skb);
+               cur_pn = ath11k_dp_rx_h_get_pn(ar, skb);
                if (cur_pn != last_pn + 1)
                        return false;
                last_pn = cur_pn;
@@ -3439,14 +3452,14 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar,
        bool more_frags;
 
        rx_desc = (struct hal_rx_desc *)msdu->data;
-       peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(rx_desc);
-       tid = ath11k_dp_rx_h_mpdu_start_tid(rx_desc);
-       seqno = ath11k_dp_rx_h_mpdu_start_seq_no(rx_desc);
-       frag_no = ath11k_dp_rx_h_mpdu_start_frag_no(msdu);
-       more_frags = ath11k_dp_rx_h_mpdu_start_more_frags(msdu);
-
-       if (!ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(rx_desc) ||
-           !ath11k_dp_rx_h_mpdu_start_fc_valid(rx_desc) ||
+       peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(ar->ab, rx_desc);
+       tid = ath11k_dp_rx_h_mpdu_start_tid(ar->ab, rx_desc);
+       seqno = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc);
+       frag_no = ath11k_dp_rx_h_mpdu_start_frag_no(ar->ab, msdu);
+       more_frags = ath11k_dp_rx_h_mpdu_start_more_frags(ar->ab, msdu);
+
+       if (!ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(ar->ab, rx_desc) ||
+           !ath11k_dp_rx_h_mpdu_start_fc_valid(ar->ab, rx_desc) ||
            tid > IEEE80211_NUM_TIDS)
                return -EINVAL;
 
@@ -3484,7 +3497,7 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar,
        if (frag_no > __fls(rx_tid->rx_frag_bitmap))
                __skb_queue_tail(&rx_tid->rx_frags, msdu);
        else
-               ath11k_dp_rx_h_sort_frags(&rx_tid->rx_frags, msdu);
+               ath11k_dp_rx_h_sort_frags(ar, &rx_tid->rx_frags, msdu);
 
        rx_tid->rx_frag_bitmap |= BIT(frag_no);
        if (!more_frags)
@@ -3551,6 +3564,7 @@ ath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool
        struct hal_rx_desc *rx_desc;
        u8 *hdr_status;
        u16 msdu_len;
+       u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
 
        spin_lock_bh(&rx_ring->idr_lock);
        msdu = idr_find(&rx_ring->bufs_idr, buf_id);
@@ -3586,9 +3600,9 @@ ath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool
        }
 
        rx_desc = (struct hal_rx_desc *)msdu->data;
-       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc);
-       if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) {
-               hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc);
+       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, rx_desc);
+       if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) {
+               hdr_status = ath11k_dp_rx_h_80211_hdr(ar->ab, rx_desc);
                ath11k_warn(ar->ab, "invalid msdu leng %u", msdu_len);
                ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status,
                                sizeof(struct ieee80211_hdr));
@@ -3598,7 +3612,7 @@ ath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool
                goto exit;
        }
 
-       skb_put(msdu, HAL_RX_DESC_SIZE + msdu_len);
+       skb_put(msdu, hal_rx_desc_sz + msdu_len);
 
        if (ath11k_dp_rx_frag_h_mpdu(ar, msdu, ring_desc)) {
                dev_kfree_skb_any(msdu);
@@ -3732,7 +3746,7 @@ static void ath11k_dp_rx_null_q_desc_sg_drop(struct ath11k *ar,
        int n_buffs;
 
        n_buffs = DIV_ROUND_UP(msdu_len,
-                              (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE));
+                              (DP_RX_BUFFER_SIZE - ar->ab->hw_params.hal_desc_sz));
 
        skb_queue_walk_safe(msdu_list, skb, tmp) {
                rxcb = ATH11K_SKB_RXCB(skb);
@@ -3753,19 +3767,22 @@ static int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu,
 {
        u16 msdu_len;
        struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data;
+       struct rx_attention *rx_attention;
        u8 l3pad_bytes;
        struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
 
-       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(desc);
+       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc);
 
-       if (!rxcb->is_frag && ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE)) {
+       if (!rxcb->is_frag && ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE)) {
                /* First buffer will be freed by the caller, so deduct it's length */
-               msdu_len = msdu_len - (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE);
+               msdu_len = msdu_len - (DP_RX_BUFFER_SIZE - hal_rx_desc_sz);
                ath11k_dp_rx_null_q_desc_sg_drop(ar, msdu_len, msdu_list);
                return -EINVAL;
        }
 
-       if (!ath11k_dp_rx_h_attn_msdu_done(desc)) {
+       rx_attention = ath11k_dp_rx_get_attention(ar->ab, desc);
+       if (!ath11k_dp_rx_h_attn_msdu_done(rx_attention)) {
                ath11k_warn(ar->ab,
                            "msdu_done bit not set in null_q_des processing\n");
                __skb_queue_purge(msdu_list);
@@ -3781,25 +3798,25 @@ static int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu,
         * This error can show up both in a REO destination or WBM release ring.
         */
 
-       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(desc);
-       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(desc);
+       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ar->ab, desc);
+       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ar->ab, desc);
 
        if (rxcb->is_frag) {
-               skb_pull(msdu, HAL_RX_DESC_SIZE);
+               skb_pull(msdu, hal_rx_desc_sz);
        } else {
-               l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(desc);
+               l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc);
 
-               if ((HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE)
+               if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE)
                        return -EINVAL;
 
-               skb_put(msdu, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len);
-               skb_pull(msdu, HAL_RX_DESC_SIZE + l3pad_bytes);
+               skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
+               skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
        }
        ath11k_dp_rx_h_ppdu(ar, desc, status);
 
        ath11k_dp_rx_h_mpdu(ar, msdu, desc, status);
 
-       rxcb->tid = ath11k_dp_rx_h_mpdu_start_tid(desc);
+       rxcb->tid = ath11k_dp_rx_h_mpdu_start_tid(ar->ab, desc);
 
        /* Please note that caller will having the access to msdu and completing
         * rx with mac80211. Need not worry about cleaning up amsdu_list.
@@ -3846,14 +3863,15 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
        struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data;
        u8 l3pad_bytes;
        struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
 
-       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(desc);
-       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(desc);
+       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ar->ab, desc);
+       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ar->ab, desc);
 
-       l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(desc);
-       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(desc);
-       skb_put(msdu, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len);
-       skb_pull(msdu, HAL_RX_DESC_SIZE + l3pad_bytes);
+       l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc);
+       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc);
+       skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
+       skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
 
        ath11k_dp_rx_h_ppdu(ar, desc, status);
 
@@ -4595,10 +4613,10 @@ ath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar, int mac_id,
                        rx_desc = (struct hal_rx_desc *)msdu->data;
 
                        rx_pkt_offset = sizeof(struct hal_rx_desc);
-                       l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(rx_desc);
+                       l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc);
 
                        if (is_first_msdu) {
-                               if (!ath11k_dp_rxdesc_mpdu_valid(rx_desc)) {
+                               if (!ath11k_dp_rxdesc_mpdu_valid(ar->ab, rx_desc)) {
                                        drop_mpdu = true;
                                        dev_kfree_skb_any(msdu);
                                        msdu = NULL;
@@ -4607,7 +4625,7 @@ ath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar, int mac_id,
                                }
 
                                msdu_ppdu_id =
-                                       ath11k_dp_rxdesc_get_ppduid(rx_desc);
+                                       ath11k_dp_rxdesc_get_ppduid(ar->ab, rx_desc);
 
                                if (ath11k_dp_rx_mon_comp_ppduid(msdu_ppdu_id,
                                                                 ppdu_id,
@@ -4676,12 +4694,13 @@ next_msdu:
        return rx_bufs_used;
 }
 
-static void ath11k_dp_rx_msdus_set_payload(struct sk_buff *msdu)
+static void ath11k_dp_rx_msdus_set_payload(struct ath11k *ar, struct sk_buff *msdu)
 {
        u32 rx_pkt_offset, l2_hdr_offset;
 
-       rx_pkt_offset = sizeof(struct hal_rx_desc);
-       l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad((struct hal_rx_desc *)msdu->data);
+       rx_pkt_offset = ar->ab->hw_params.hal_desc_sz;
+       l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab,
+                                                     (struct hal_rx_desc *)msdu->data);
        skb_pull(msdu, rx_pkt_offset + l2_hdr_offset);
 }
 
@@ -4691,12 +4710,14 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
                            struct sk_buff *last_msdu,
                            struct ieee80211_rx_status *rxs)
 {
+       struct ath11k_base *ab = ar->ab;
        struct sk_buff *msdu, *mpdu_buf, *prev_buf;
-       u32 decap_format, wifi_hdr_len;
+       u32 wifi_hdr_len;
        struct hal_rx_desc *rx_desc;
        char *hdr_desc;
-       u8 *dest;
+       u8 *dest, decap_format;
        struct ieee80211_hdr_3addr *wh;
+       struct rx_attention *rx_attention;
 
        mpdu_buf = NULL;
 
@@ -4704,22 +4725,23 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
                goto err_merge_fail;
 
        rx_desc = (struct hal_rx_desc *)head_msdu->data;
+       rx_attention = ath11k_dp_rx_get_attention(ab, rx_desc);
 
-       if (ath11k_dp_rxdesc_get_mpdulen_err(rx_desc))
+       if (ath11k_dp_rxdesc_get_mpdulen_err(rx_attention))
                return NULL;
 
-       decap_format = ath11k_dp_rxdesc_get_decap_format(rx_desc);
+       decap_format = ath11k_dp_rx_h_msdu_start_decap_type(ab, rx_desc);
 
        ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs);
 
        if (decap_format == DP_RX_DECAP_TYPE_RAW) {
-               ath11k_dp_rx_msdus_set_payload(head_msdu);
+               ath11k_dp_rx_msdus_set_payload(ar, head_msdu);
 
                prev_buf = head_msdu;
                msdu = head_msdu->next;
 
                while (msdu) {
-                       ath11k_dp_rx_msdus_set_payload(msdu);
+                       ath11k_dp_rx_msdus_set_payload(ar, msdu);
 
                        prev_buf = msdu;
                        msdu = msdu->next;
@@ -4733,7 +4755,7 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
                u8 qos_pkt = 0;
 
                rx_desc = (struct hal_rx_desc *)head_msdu->data;
-               hdr_desc = ath11k_dp_rxdesc_get_80211hdr(rx_desc);
+               hdr_desc = ath11k_dp_rxdesc_get_80211hdr(ab, rx_desc);
 
                /* Base size */
                wifi_hdr_len = sizeof(struct ieee80211_hdr_3addr);
@@ -4750,7 +4772,7 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
 
                while (msdu) {
                        rx_desc = (struct hal_rx_desc *)msdu->data;
-                       hdr_desc = ath11k_dp_rxdesc_get_80211hdr(rx_desc);
+                       hdr_desc = ath11k_dp_rxdesc_get_80211hdr(ab, rx_desc);
 
                        if (qos_pkt) {
                                dest = skb_push(msdu, sizeof(__le16));
@@ -4760,7 +4782,7 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
                                memcpy(dest + wifi_hdr_len,
                                       (u8 *)&qos_field, sizeof(__le16));
                        }
-                       ath11k_dp_rx_msdus_set_payload(msdu);
+                       ath11k_dp_rx_msdus_set_payload(ar, msdu);
                        prev_buf = msdu;
                        msdu = msdu->next;
                }
@@ -4768,11 +4790,11 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
                if (!dest)
                        goto err_merge_fail;
 
-               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+               ath11k_dbg(ab, ATH11K_DBG_DATA,
                           "mpdu_buf %pK mpdu_buf->len %u",
                           prev_buf, prev_buf->len);
        } else {
-               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+               ath11k_dbg(ab, ATH11K_DBG_DATA,
                           "decap format %d is not supported!\n",
                           decap_format);
                goto err_merge_fail;
@@ -4782,7 +4804,7 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
 
 err_merge_fail:
        if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) {
-               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+               ath11k_dbg(ab, ATH11K_DBG_DATA,
                           "err_merge_fail mpdu_buf %pK", mpdu_buf);
                /* Free the head buffer */
                dev_kfree_skb_any(mpdu_buf);
index 1a0b9be..8bba523 100644 (file)
@@ -178,7 +178,7 @@ tcl_ring_sel:
        }
 
        if (ieee80211_vif_is_mesh(arvif->vif))
-               ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_MESH_ENABLE, 1);
+               ti.enable_mesh = true;
 
        ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE, 1);
 
@@ -792,8 +792,8 @@ int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id,
        cmd->ring_tail_off32_remote_addr_hi = (u64)tp_addr >>
                                              HAL_ADDR_MSB_REG_SHIFT;
 
-       cmd->ring_msi_addr_lo = params.msi_addr & 0xffffffff;
-       cmd->ring_msi_addr_hi = ((uint64_t)(params.msi_addr) >> 32) & 0xffffffff;
+       cmd->ring_msi_addr_lo = lower_32_bits(params.msi_addr);
+       cmd->ring_msi_addr_hi = upper_32_bits(params.msi_addr);
        cmd->msi_data = params.msi_data;
 
        cmd->intr_info = FIELD_PREP(
index 9904c0e..08e3c72 100644 (file)
@@ -89,17 +89,6 @@ static const struct hal_srng_config hw_srng_config_template[] = {
                .entry_size = sizeof(struct hal_ce_srng_src_desc) >> 2,
                .lmac_ring = false,
                .ring_dir = HAL_SRNG_DIR_SRC,
-               .reg_start = {
-                       (HAL_SEQ_WCSS_UMAC_CE0_SRC_REG +
-                        HAL_CE_DST_RING_BASE_LSB),
-                       HAL_SEQ_WCSS_UMAC_CE0_SRC_REG + HAL_CE_DST_RING_HP,
-               },
-               .reg_size = {
-                       (HAL_SEQ_WCSS_UMAC_CE1_SRC_REG -
-                        HAL_SEQ_WCSS_UMAC_CE0_SRC_REG),
-                       (HAL_SEQ_WCSS_UMAC_CE1_SRC_REG -
-                        HAL_SEQ_WCSS_UMAC_CE0_SRC_REG),
-               },
                .max_size = HAL_CE_SRC_RING_BASE_MSB_RING_SIZE,
        },
        { /* CE_DST */
@@ -108,17 +97,6 @@ static const struct hal_srng_config hw_srng_config_template[] = {
                .entry_size = sizeof(struct hal_ce_srng_dest_desc) >> 2,
                .lmac_ring = false,
                .ring_dir = HAL_SRNG_DIR_SRC,
-               .reg_start = {
-                       (HAL_SEQ_WCSS_UMAC_CE0_DST_REG +
-                        HAL_CE_DST_RING_BASE_LSB),
-                       HAL_SEQ_WCSS_UMAC_CE0_DST_REG + HAL_CE_DST_RING_HP,
-               },
-               .reg_size = {
-                       (HAL_SEQ_WCSS_UMAC_CE1_DST_REG -
-                        HAL_SEQ_WCSS_UMAC_CE0_DST_REG),
-                       (HAL_SEQ_WCSS_UMAC_CE1_DST_REG -
-                        HAL_SEQ_WCSS_UMAC_CE0_DST_REG),
-               },
                .max_size = HAL_CE_DST_RING_BASE_MSB_RING_SIZE,
        },
        { /* CE_DST_STATUS */
@@ -127,18 +105,6 @@ static const struct hal_srng_config hw_srng_config_template[] = {
                .entry_size = sizeof(struct hal_ce_srng_dst_status_desc) >> 2,
                .lmac_ring = false,
                .ring_dir = HAL_SRNG_DIR_DST,
-               .reg_start = {
-                       (HAL_SEQ_WCSS_UMAC_CE0_DST_REG +
-                        HAL_CE_DST_STATUS_RING_BASE_LSB),
-                       (HAL_SEQ_WCSS_UMAC_CE0_DST_REG +
-                        HAL_CE_DST_STATUS_RING_HP),
-               },
-               .reg_size = {
-                       (HAL_SEQ_WCSS_UMAC_CE1_DST_REG -
-                        HAL_SEQ_WCSS_UMAC_CE0_DST_REG),
-                       (HAL_SEQ_WCSS_UMAC_CE1_DST_REG -
-                        HAL_SEQ_WCSS_UMAC_CE0_DST_REG),
-               },
                .max_size = HAL_CE_DST_STATUS_RING_BASE_MSB_RING_SIZE,
        },
        { /* WBM_IDLE_LINK */
@@ -147,11 +113,6 @@ static const struct hal_srng_config hw_srng_config_template[] = {
                .entry_size = sizeof(struct hal_wbm_link_desc) >> 2,
                .lmac_ring = false,
                .ring_dir = HAL_SRNG_DIR_SRC,
-               .reg_start = {
-                       (HAL_SEQ_WCSS_UMAC_WBM_REG +
-                        HAL_WBM_IDLE_LINK_RING_BASE_LSB),
-                       (HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_HP),
-               },
                .max_size = HAL_WBM_IDLE_LINK_RING_BASE_MSB_RING_SIZE,
        },
        { /* SW2WBM_RELEASE */
@@ -160,11 +121,6 @@ static const struct hal_srng_config hw_srng_config_template[] = {
                .entry_size = sizeof(struct hal_wbm_release_ring) >> 2,
                .lmac_ring = false,
                .ring_dir = HAL_SRNG_DIR_SRC,
-               .reg_start = {
-                       (HAL_SEQ_WCSS_UMAC_WBM_REG +
-                        HAL_WBM_RELEASE_RING_BASE_LSB),
-                       (HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_RELEASE_RING_HP),
-               },
                .max_size = HAL_SW2WBM_RELEASE_RING_BASE_MSB_RING_SIZE,
        },
        { /* WBM2SW_RELEASE */
@@ -173,16 +129,6 @@ static const struct hal_srng_config hw_srng_config_template[] = {
                .entry_size = sizeof(struct hal_wbm_release_ring) >> 2,
                .lmac_ring = false,
                .ring_dir = HAL_SRNG_DIR_DST,
-               .reg_start = {
-                       (HAL_SEQ_WCSS_UMAC_WBM_REG +
-                        HAL_WBM0_RELEASE_RING_BASE_LSB),
-                       (HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_HP),
-               },
-               .reg_size = {
-                       (HAL_WBM1_RELEASE_RING_BASE_LSB -
-                        HAL_WBM0_RELEASE_RING_BASE_LSB),
-                       (HAL_WBM1_RELEASE_RING_HP - HAL_WBM0_RELEASE_RING_HP),
-               },
                .max_size = HAL_WBM2SW_RELEASE_RING_BASE_MSB_RING_SIZE,
        },
        { /* RXDMA_BUF */
@@ -955,7 +901,7 @@ void ath11k_hal_setup_link_idle_list(struct ath11k_base *ab,
        /* Enable the SRNG */
        ath11k_hif_write32(ab,
                           HAL_SEQ_WCSS_UMAC_WBM_REG +
-                          HAL_WBM_IDLE_LINK_RING_MISC_ADDR, 0x40);
+                          HAL_WBM_IDLE_LINK_RING_MISC_ADDR(ab), 0x40);
 }
 
 int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
@@ -1234,6 +1180,46 @@ static int ath11k_hal_srng_create_config(struct ath11k_base *ab)
        s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_BASE_LSB(ab);
        s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP;
 
+       s = &hal->srng_config[HAL_CE_SRC];
+       s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_BASE_LSB;
+       s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_HP;
+       s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab);
+       s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab);
+
+       s = &hal->srng_config[HAL_CE_DST];
+       s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_BASE_LSB;
+       s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_HP;
+       s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);
+       s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);
+
+       s = &hal->srng_config[HAL_CE_DST_STATUS];
+       s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) +
+               HAL_CE_DST_STATUS_RING_BASE_LSB;
+       s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_STATUS_RING_HP;
+       s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);
+       s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);
+
+       s = &hal->srng_config[HAL_WBM_IDLE_LINK];
+       s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_BASE_LSB(ab);
+       s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_HP;
+
+       s = &hal->srng_config[HAL_SW2WBM_RELEASE];
+       s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_RELEASE_RING_BASE_LSB(ab);
+       s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_RELEASE_RING_HP;
+
+       s = &hal->srng_config[HAL_WBM2SW_RELEASE];
+       s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_BASE_LSB(ab);
+       s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_HP;
+       s->reg_size[0] = HAL_WBM1_RELEASE_RING_BASE_LSB(ab) -
+               HAL_WBM0_RELEASE_RING_BASE_LSB(ab);
+       s->reg_size[1] = HAL_WBM1_RELEASE_RING_HP - HAL_WBM0_RELEASE_RING_HP;
+
        return 0;
 }
 
index 1f1b29c..91d1428 100644 (file)
@@ -39,14 +39,22 @@ struct ath11k_base;
 #define HAL_SHADOW_REG(x) (HAL_SHADOW_BASE_ADDR + (4 * (x)))
 
 /* WCSS Relative address */
+#define HAL_SEQ_WCSS_UMAC_OFFSET               0x00a00000
 #define HAL_SEQ_WCSS_UMAC_REO_REG              0x00a38000
 #define HAL_SEQ_WCSS_UMAC_TCL_REG              0x00a44000
-#define HAL_SEQ_WCSS_UMAC_CE0_SRC_REG          0x00a00000
-#define HAL_SEQ_WCSS_UMAC_CE0_DST_REG          0x00a01000
-#define HAL_SEQ_WCSS_UMAC_CE1_SRC_REG          0x00a02000
-#define HAL_SEQ_WCSS_UMAC_CE1_DST_REG          0x00a03000
+#define HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(x) \
+               (ab->hw_params.regs->hal_seq_wcss_umac_ce0_src_reg)
+#define HAL_SEQ_WCSS_UMAC_CE0_DST_REG(x) \
+               (ab->hw_params.regs->hal_seq_wcss_umac_ce0_dst_reg)
+#define HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(x) \
+               (ab->hw_params.regs->hal_seq_wcss_umac_ce1_src_reg)
+#define HAL_SEQ_WCSS_UMAC_CE1_DST_REG(x) \
+               (ab->hw_params.regs->hal_seq_wcss_umac_ce1_dst_reg)
 #define HAL_SEQ_WCSS_UMAC_WBM_REG              0x00a34000
 
+#define HAL_CE_WFSS_CE_REG_BASE                        0x01b80000
+#define HAL_WLAON_REG_BASE                     0x01f80000
+
 /* SW2TCL(x) R0 ring configuration address */
 #define HAL_TCL1_RING_CMN_CTRL_REG             0x00000014
 #define HAL_TCL1_RING_DSCP_TID_MAP             0x0000002c
@@ -197,8 +205,10 @@ struct ath11k_base;
 #define HAL_REO_STATUS_HP(ab)                  ab->hw_params.regs->hal_reo_status_hp
 
 /* WBM Idle R0 address */
-#define HAL_WBM_IDLE_LINK_RING_BASE_LSB                0x00000860
-#define HAL_WBM_IDLE_LINK_RING_MISC_ADDR       0x00000870
+#define HAL_WBM_IDLE_LINK_RING_BASE_LSB(x) \
+               (ab->hw_params.regs->hal_wbm_idle_link_ring_base_lsb)
+#define HAL_WBM_IDLE_LINK_RING_MISC_ADDR(x) \
+               (ab->hw_params.regs->hal_wbm_idle_link_ring_misc)
 #define HAL_WBM_R0_IDLE_LIST_CONTROL_ADDR      0x00000048
 #define HAL_WBM_R0_IDLE_LIST_SIZE_ADDR         0x0000004c
 #define HAL_WBM_SCATTERED_RING_BASE_LSB                0x00000058
@@ -213,14 +223,17 @@ struct ath11k_base;
 #define HAL_WBM_IDLE_LINK_RING_HP              0x000030b0
 
 /* SW2WBM R0 release address */
-#define HAL_WBM_RELEASE_RING_BASE_LSB          0x000001d8
+#define HAL_WBM_RELEASE_RING_BASE_LSB(x) \
+               (ab->hw_params.regs->hal_wbm_release_ring_base_lsb)
 
 /* SW2WBM R2 release address */
 #define HAL_WBM_RELEASE_RING_HP                        0x00003018
 
 /* WBM2SW R0 release address */
-#define HAL_WBM0_RELEASE_RING_BASE_LSB         0x00000910
-#define HAL_WBM1_RELEASE_RING_BASE_LSB         0x00000968
+#define HAL_WBM0_RELEASE_RING_BASE_LSB(x) \
+               (ab->hw_params.regs->hal_wbm0_release_ring_base_lsb)
+#define HAL_WBM1_RELEASE_RING_BASE_LSB(x) \
+               (ab->hw_params.regs->hal_wbm1_release_ring_base_lsb)
 
 /* WBM2SW R2 release address */
 #define HAL_WBM0_RELEASE_RING_HP               0x000030c0
@@ -303,8 +316,6 @@ struct ath11k_base;
 #define HAL_WBM2SW_RELEASE_RING_BASE_MSB_RING_SIZE     0x000fffff
 #define HAL_RXDMA_RING_MAX_SIZE                                0x0000ffff
 
-#define HAL_RX_DESC_SIZE (sizeof(struct hal_rx_desc))
-
 /* Add any other errors here and return them in
  * ath11k_hal_rx_desc_get_err().
  */
index 1b713cb..d54ec6a 100644 (file)
@@ -949,16 +949,17 @@ struct hal_reo_flush_cache {
 #define HAL_TCL_DATA_CMD_INFO1_TO_FW           BIT(21)
 #define HAL_TCL_DATA_CMD_INFO1_PKT_OFFSET      GENMASK(31, 23)
 
-#define HAL_TCL_DATA_CMD_INFO2_BUF_TIMESTAMP   GENMASK(18, 0)
-#define HAL_TCL_DATA_CMD_INFO2_BUF_T_VALID     BIT(19)
-#define HAL_TCL_DATA_CMD_INFO2_MESH_ENABLE     BIT(20)
-#define HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE   BIT(21)
-#define HAL_TCL_DATA_CMD_INFO2_TID             GENMASK(25, 22)
-#define HAL_TCL_DATA_CMD_INFO2_LMAC_ID         GENMASK(27, 26)
+#define HAL_TCL_DATA_CMD_INFO2_BUF_TIMESTAMP           GENMASK(18, 0)
+#define HAL_TCL_DATA_CMD_INFO2_BUF_T_VALID             BIT(19)
+#define HAL_IPQ8074_TCL_DATA_CMD_INFO2_MESH_ENABLE     BIT(20)
+#define HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE           BIT(21)
+#define HAL_TCL_DATA_CMD_INFO2_TID                     GENMASK(25, 22)
+#define HAL_TCL_DATA_CMD_INFO2_LMAC_ID                 GENMASK(27, 26)
 
 #define HAL_TCL_DATA_CMD_INFO3_DSCP_TID_TABLE_IDX      GENMASK(5, 0)
 #define HAL_TCL_DATA_CMD_INFO3_SEARCH_INDEX            GENMASK(25, 6)
 #define HAL_TCL_DATA_CMD_INFO3_CACHE_SET_NUM           GENMASK(29, 26)
+#define HAL_QCN9074_TCL_DATA_CMD_INFO3_MESH_ENABLE     GENMASK(31, 30)
 
 #define HAL_TCL_DATA_CMD_INFO4_RING_ID                 GENMASK(27, 20)
 #define HAL_TCL_DATA_CMD_INFO4_LOOPING_COUNT           GENMASK(31, 28)
index 569e790..c8929de 100644 (file)
@@ -75,6 +75,9 @@ void ath11k_hal_tx_cmd_desc_setup(struct ath11k_base *ab, void *cmd,
                         FIELD_PREP(HAL_TCL_DATA_CMD_INFO3_CACHE_SET_NUM,
                                    ti->bss_ast_hash);
        tcl_cmd->info4 = 0;
+
+       if (ti->enable_mesh)
+               ab->hw_params.hw_ops->tx_mesh_enable(ab, tcl_cmd);
 }
 
 void ath11k_hal_tx_set_dscp_tid_map(struct ath11k_base *ab, int id)
index c291e59..36f4f6f 100644 (file)
@@ -34,6 +34,7 @@ struct hal_tx_info {
        u8 search_type; /* %HAL_TX_ADDR_SEARCH_ */
        u8 lmac_id;
        u8 dscp_tid_tbl_idx;
+       bool enable_mesh;
 };
 
 /* TODO: Check if the actual desc macros can be used instead */
index 6285c52..e9366f7 100644 (file)
@@ -28,6 +28,7 @@ struct ath11k_hif_ops {
                                u32 *msi_addr_hi);
        void (*ce_irq_enable)(struct ath11k_base *ab);
        void (*ce_irq_disable)(struct ath11k_base *ab);
+       void (*get_ce_msi_idx)(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx);
 };
 
 static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab)
@@ -124,4 +125,13 @@ static inline void ath11k_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_
 
        ab->hif.ops->get_msi_address(ab, msi_addr_lo, msi_addr_hi);
 }
+
+static inline void ath11k_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
+                                        u32 *msi_data_idx)
+{
+       if (ab->hif.ops->get_ce_msi_idx)
+               ab->hif.ops->get_ce_msi_idx(ab, ce_id, msi_data_idx);
+       else
+               *msi_data_idx = ce_id;
+}
 #endif /* _HIF_H_ */
index 66331da..377ae8d 100644 (file)
@@ -31,6 +31,20 @@ static u8 ath11k_hw_ipq6018_mac_from_pdev_id(int pdev_idx)
        return pdev_idx;
 }
 
+static void ath11k_hw_ipq8074_tx_mesh_enable(struct ath11k_base *ab,
+                                            struct hal_tcl_data_cmd *tcl_cmd)
+{
+       tcl_cmd->info2 |= FIELD_PREP(HAL_IPQ8074_TCL_DATA_CMD_INFO2_MESH_ENABLE,
+                                    true);
+}
+
+static void ath11k_hw_qcn9074_tx_mesh_enable(struct ath11k_base *ab,
+                                            struct hal_tcl_data_cmd *tcl_cmd)
+{
+       tcl_cmd->info3 |= FIELD_PREP(HAL_QCN9074_TCL_DATA_CMD_INFO3_MESH_ENABLE,
+                                    true);
+}
+
 static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab,
                                           struct target_resource_config *config)
 {
@@ -155,11 +169,358 @@ static int ath11k_hw_mac_id_to_srng_id_qca6390(struct ath11k_hw_params *hw,
        return mac_id;
 }
 
+static bool ath11k_hw_ipq8074_rx_desc_get_first_msdu(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU,
+                          __le32_to_cpu(desc->u.ipq8074.msdu_end.info2));
+}
+
+static bool ath11k_hw_ipq8074_rx_desc_get_last_msdu(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MSDU_END_INFO2_LAST_MSDU,
+                          __le32_to_cpu(desc->u.ipq8074.msdu_end.info2));
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_l3_pad_bytes(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_END_INFO2_L3_HDR_PADDING,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_end.info2));
+}
+
+static u8 *ath11k_hw_ipq8074_rx_desc_get_hdr_status(struct hal_rx_desc *desc)
+{
+       return desc->u.ipq8074.hdr_status;
+}
+
+static bool ath11k_hw_ipq8074_rx_desc_encrypt_valid(struct hal_rx_desc *desc)
+{
+       return __le32_to_cpu(desc->u.ipq8074.mpdu_start.info1) &
+              RX_MPDU_START_INFO1_ENCRYPT_INFO_VALID;
+}
+
+static u32 ath11k_hw_ipq8074_rx_desc_get_encrypt_type(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MPDU_START_INFO2_ENC_TYPE,
+                        __le32_to_cpu(desc->u.ipq8074.mpdu_start.info2));
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_decap_type(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_start.info2));
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_mesh_ctl(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO2_MESH_CTRL_PRESENT,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_start.info2));
+}
+
+static bool ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID,
+                          __le32_to_cpu(desc->u.ipq8074.mpdu_start.info1));
+}
+
+static bool ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_FCTRL_VALID,
+                          __le32_to_cpu(desc->u.ipq8074.mpdu_start.info1));
+}
+
+static u16 ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_NUM,
+                        __le32_to_cpu(desc->u.ipq8074.mpdu_start.info1));
+}
+
+static u16 ath11k_hw_ipq8074_rx_desc_get_msdu_len(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO1_MSDU_LENGTH,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_start.info1));
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_msdu_sgi(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_SGI,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_start.info3));
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_msdu_rate_mcs(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_RATE_MCS,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_start.info3));
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_msdu_rx_bw(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_RECV_BW,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_start.info3));
+}
+
+static u32 ath11k_hw_ipq8074_rx_desc_get_msdu_freq(struct hal_rx_desc *desc)
+{
+       return __le32_to_cpu(desc->u.ipq8074.msdu_start.phy_meta_data);
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_PKT_TYPE,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_start.info3));
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_msdu_nss(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_MIMO_SS_BITMAP,
+                        __le32_to_cpu(desc->u.ipq8074.msdu_start.info3));
+}
+
+static u8 ath11k_hw_ipq8074_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MPDU_START_INFO2_TID,
+                        __le32_to_cpu(desc->u.ipq8074.mpdu_start.info2));
+}
+
+static u16 ath11k_hw_ipq8074_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc)
+{
+       return __le16_to_cpu(desc->u.ipq8074.mpdu_start.sw_peer_id);
+}
+
+static void ath11k_hw_ipq8074_rx_desc_copy_attn_end(struct hal_rx_desc *fdesc,
+                                                   struct hal_rx_desc *ldesc)
+{
+       memcpy((u8 *)&fdesc->u.ipq8074.msdu_end, (u8 *)&ldesc->u.ipq8074.msdu_end,
+              sizeof(struct rx_msdu_end_ipq8074));
+       memcpy((u8 *)&fdesc->u.ipq8074.attention, (u8 *)&ldesc->u.ipq8074.attention,
+              sizeof(struct rx_attention));
+       memcpy((u8 *)&fdesc->u.ipq8074.mpdu_end, (u8 *)&ldesc->u.ipq8074.mpdu_end,
+              sizeof(struct rx_mpdu_end));
+}
+
+static u32 ath11k_hw_ipq8074_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(HAL_TLV_HDR_TAG,
+                        __le32_to_cpu(desc->u.ipq8074.mpdu_start_tag));
+}
+
+static u32 ath11k_hw_ipq8074_rx_desc_get_mpdu_ppdu_id(struct hal_rx_desc *desc)
+{
+       return __le16_to_cpu(desc->u.ipq8074.mpdu_start.phy_ppdu_id);
+}
+
+static void ath11k_hw_ipq8074_rx_desc_set_msdu_len(struct hal_rx_desc *desc, u16 len)
+{
+       u32 info = __le32_to_cpu(desc->u.ipq8074.msdu_start.info1);
+
+       info &= ~RX_MSDU_START_INFO1_MSDU_LENGTH;
+       info |= FIELD_PREP(RX_MSDU_START_INFO1_MSDU_LENGTH, len);
+
+       desc->u.ipq8074.msdu_start.info1 = __cpu_to_le32(info);
+}
+
+static
+struct rx_attention *ath11k_hw_ipq8074_rx_desc_get_attention(struct hal_rx_desc *desc)
+{
+       return &desc->u.ipq8074.attention;
+}
+
+static u8 *ath11k_hw_ipq8074_rx_desc_get_msdu_payload(struct hal_rx_desc *desc)
+{
+       return &desc->u.ipq8074.msdu_payload[0];
+}
+
+static bool ath11k_hw_qcn9074_rx_desc_get_first_msdu(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MSDU_END_INFO4_FIRST_MSDU,
+                          __le16_to_cpu(desc->u.qcn9074.msdu_end.info4));
+}
+
+static bool ath11k_hw_qcn9074_rx_desc_get_last_msdu(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MSDU_END_INFO4_LAST_MSDU,
+                          __le16_to_cpu(desc->u.qcn9074.msdu_end.info4));
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_l3_pad_bytes(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_END_INFO4_L3_HDR_PADDING,
+                        __le16_to_cpu(desc->u.qcn9074.msdu_end.info4));
+}
+
+static u8 *ath11k_hw_qcn9074_rx_desc_get_hdr_status(struct hal_rx_desc *desc)
+{
+       return desc->u.qcn9074.hdr_status;
+}
+
+static bool ath11k_hw_qcn9074_rx_desc_encrypt_valid(struct hal_rx_desc *desc)
+{
+       return __le32_to_cpu(desc->u.qcn9074.mpdu_start.info11) &
+              RX_MPDU_START_INFO11_ENCRYPT_INFO_VALID;
+}
+
+static u32 ath11k_hw_qcn9074_rx_desc_get_encrypt_type(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MPDU_START_INFO9_ENC_TYPE,
+                        __le32_to_cpu(desc->u.qcn9074.mpdu_start.info9));
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_decap_type(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT,
+                        __le32_to_cpu(desc->u.qcn9074.msdu_start.info2));
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_mesh_ctl(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO2_MESH_CTRL_PRESENT,
+                        __le32_to_cpu(desc->u.qcn9074.msdu_start.info2));
+}
+
+static bool ath11k_hw_qcn9074_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MPDU_START_INFO11_MPDU_SEQ_CTRL_VALID,
+                          __le32_to_cpu(desc->u.qcn9074.mpdu_start.info11));
+}
+
+static bool ath11k_hw_qcn9074_rx_desc_get_mpdu_fc_valid(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MPDU_START_INFO11_MPDU_FCTRL_VALID,
+                          __le32_to_cpu(desc->u.qcn9074.mpdu_start.info11));
+}
+
+static u16 ath11k_hw_qcn9074_rx_desc_get_mpdu_start_seq_no(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MPDU_START_INFO11_MPDU_SEQ_NUM,
+                        __le32_to_cpu(desc->u.qcn9074.mpdu_start.info11));
+}
+
+static u16 ath11k_hw_qcn9074_rx_desc_get_msdu_len(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO1_MSDU_LENGTH,
+                        __le32_to_cpu(desc->u.qcn9074.msdu_start.info1));
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_msdu_sgi(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_SGI,
+                        __le32_to_cpu(desc->u.qcn9074.msdu_start.info3));
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_msdu_rate_mcs(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_RATE_MCS,
+                        __le32_to_cpu(desc->u.qcn9074.msdu_start.info3));
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_msdu_rx_bw(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_RECV_BW,
+                        __le32_to_cpu(desc->u.qcn9074.msdu_start.info3));
+}
+
+static u32 ath11k_hw_qcn9074_rx_desc_get_msdu_freq(struct hal_rx_desc *desc)
+{
+       return __le32_to_cpu(desc->u.qcn9074.msdu_start.phy_meta_data);
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_PKT_TYPE,
+                        __le32_to_cpu(desc->u.qcn9074.msdu_start.info3));
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_msdu_nss(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_MIMO_SS_BITMAP,
+                        __le32_to_cpu(desc->u.qcn9074.msdu_start.info3));
+}
+
+static u8 ath11k_hw_qcn9074_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MPDU_START_INFO9_TID,
+                        __le32_to_cpu(desc->u.qcn9074.mpdu_start.info9));
+}
+
+static u16 ath11k_hw_qcn9074_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc)
+{
+       return __le16_to_cpu(desc->u.qcn9074.mpdu_start.sw_peer_id);
+}
+
+static void ath11k_hw_qcn9074_rx_desc_copy_attn_end(struct hal_rx_desc *fdesc,
+                                                   struct hal_rx_desc *ldesc)
+{
+       memcpy((u8 *)&fdesc->u.qcn9074.msdu_end, (u8 *)&ldesc->u.qcn9074.msdu_end,
+              sizeof(struct rx_msdu_end_qcn9074));
+       memcpy((u8 *)&fdesc->u.qcn9074.attention, (u8 *)&ldesc->u.qcn9074.attention,
+              sizeof(struct rx_attention));
+       memcpy((u8 *)&fdesc->u.qcn9074.mpdu_end, (u8 *)&ldesc->u.qcn9074.mpdu_end,
+              sizeof(struct rx_mpdu_end));
+}
+
+static u32 ath11k_hw_qcn9074_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(HAL_TLV_HDR_TAG,
+                        __le32_to_cpu(desc->u.qcn9074.mpdu_start_tag));
+}
+
+static u32 ath11k_hw_qcn9074_rx_desc_get_mpdu_ppdu_id(struct hal_rx_desc *desc)
+{
+       return __le16_to_cpu(desc->u.qcn9074.mpdu_start.phy_ppdu_id);
+}
+
+static void ath11k_hw_qcn9074_rx_desc_set_msdu_len(struct hal_rx_desc *desc, u16 len)
+{
+       u32 info = __le32_to_cpu(desc->u.qcn9074.msdu_start.info1);
+
+       info &= ~RX_MSDU_START_INFO1_MSDU_LENGTH;
+       info |= FIELD_PREP(RX_MSDU_START_INFO1_MSDU_LENGTH, len);
+
+       desc->u.qcn9074.msdu_start.info1 = __cpu_to_le32(info);
+}
+
+static
+struct rx_attention *ath11k_hw_qcn9074_rx_desc_get_attention(struct hal_rx_desc *desc)
+{
+       return &desc->u.qcn9074.attention;
+}
+
+static u8 *ath11k_hw_qcn9074_rx_desc_get_msdu_payload(struct hal_rx_desc *desc)
+{
+       return &desc->u.qcn9074.msdu_payload[0];
+}
+
 const struct ath11k_hw_ops ipq8074_ops = {
        .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id,
        .wmi_init_config = ath11k_init_wmi_config_ipq8074,
        .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_ipq8074,
        .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_ipq8074,
+       .tx_mesh_enable = ath11k_hw_ipq8074_tx_mesh_enable,
+       .rx_desc_get_first_msdu = ath11k_hw_ipq8074_rx_desc_get_first_msdu,
+       .rx_desc_get_last_msdu = ath11k_hw_ipq8074_rx_desc_get_last_msdu,
+       .rx_desc_get_l3_pad_bytes = ath11k_hw_ipq8074_rx_desc_get_l3_pad_bytes,
+       .rx_desc_get_hdr_status = ath11k_hw_ipq8074_rx_desc_get_hdr_status,
+       .rx_desc_encrypt_valid = ath11k_hw_ipq8074_rx_desc_encrypt_valid,
+       .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type,
+       .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type,
+       .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl,
+       .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld,
+       .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid,
+       .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no,
+       .rx_desc_get_msdu_len = ath11k_hw_ipq8074_rx_desc_get_msdu_len,
+       .rx_desc_get_msdu_sgi = ath11k_hw_ipq8074_rx_desc_get_msdu_sgi,
+       .rx_desc_get_msdu_rate_mcs = ath11k_hw_ipq8074_rx_desc_get_msdu_rate_mcs,
+       .rx_desc_get_msdu_rx_bw = ath11k_hw_ipq8074_rx_desc_get_msdu_rx_bw,
+       .rx_desc_get_msdu_freq = ath11k_hw_ipq8074_rx_desc_get_msdu_freq,
+       .rx_desc_get_msdu_pkt_type = ath11k_hw_ipq8074_rx_desc_get_msdu_pkt_type,
+       .rx_desc_get_msdu_nss = ath11k_hw_ipq8074_rx_desc_get_msdu_nss,
+       .rx_desc_get_mpdu_tid = ath11k_hw_ipq8074_rx_desc_get_mpdu_tid,
+       .rx_desc_get_mpdu_peer_id = ath11k_hw_ipq8074_rx_desc_get_mpdu_peer_id,
+       .rx_desc_copy_attn_end_tlv = ath11k_hw_ipq8074_rx_desc_copy_attn_end,
+       .rx_desc_get_mpdu_start_tag = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_tag,
+       .rx_desc_get_mpdu_ppdu_id = ath11k_hw_ipq8074_rx_desc_get_mpdu_ppdu_id,
+       .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len,
+       .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention,
+       .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload,
 };
 
 const struct ath11k_hw_ops ipq6018_ops = {
@@ -167,6 +528,33 @@ const struct ath11k_hw_ops ipq6018_ops = {
        .wmi_init_config = ath11k_init_wmi_config_ipq8074,
        .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_ipq8074,
        .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_ipq8074,
+       .tx_mesh_enable = ath11k_hw_ipq8074_tx_mesh_enable,
+       .rx_desc_get_first_msdu = ath11k_hw_ipq8074_rx_desc_get_first_msdu,
+       .rx_desc_get_last_msdu = ath11k_hw_ipq8074_rx_desc_get_last_msdu,
+       .rx_desc_get_l3_pad_bytes = ath11k_hw_ipq8074_rx_desc_get_l3_pad_bytes,
+       .rx_desc_get_hdr_status = ath11k_hw_ipq8074_rx_desc_get_hdr_status,
+       .rx_desc_encrypt_valid = ath11k_hw_ipq8074_rx_desc_encrypt_valid,
+       .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type,
+       .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type,
+       .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl,
+       .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld,
+       .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid,
+       .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no,
+       .rx_desc_get_msdu_len = ath11k_hw_ipq8074_rx_desc_get_msdu_len,
+       .rx_desc_get_msdu_sgi = ath11k_hw_ipq8074_rx_desc_get_msdu_sgi,
+       .rx_desc_get_msdu_rate_mcs = ath11k_hw_ipq8074_rx_desc_get_msdu_rate_mcs,
+       .rx_desc_get_msdu_rx_bw = ath11k_hw_ipq8074_rx_desc_get_msdu_rx_bw,
+       .rx_desc_get_msdu_freq = ath11k_hw_ipq8074_rx_desc_get_msdu_freq,
+       .rx_desc_get_msdu_pkt_type = ath11k_hw_ipq8074_rx_desc_get_msdu_pkt_type,
+       .rx_desc_get_msdu_nss = ath11k_hw_ipq8074_rx_desc_get_msdu_nss,
+       .rx_desc_get_mpdu_tid = ath11k_hw_ipq8074_rx_desc_get_mpdu_tid,
+       .rx_desc_get_mpdu_peer_id = ath11k_hw_ipq8074_rx_desc_get_mpdu_peer_id,
+       .rx_desc_copy_attn_end_tlv = ath11k_hw_ipq8074_rx_desc_copy_attn_end,
+       .rx_desc_get_mpdu_start_tag = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_tag,
+       .rx_desc_get_mpdu_ppdu_id = ath11k_hw_ipq8074_rx_desc_get_mpdu_ppdu_id,
+       .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len,
+       .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention,
+       .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload,
 };
 
 const struct ath11k_hw_ops qca6390_ops = {
@@ -174,6 +562,67 @@ const struct ath11k_hw_ops qca6390_ops = {
        .wmi_init_config = ath11k_init_wmi_config_qca6390,
        .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_qca6390,
        .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_qca6390,
+       .tx_mesh_enable = ath11k_hw_ipq8074_tx_mesh_enable,
+       .rx_desc_get_first_msdu = ath11k_hw_ipq8074_rx_desc_get_first_msdu,
+       .rx_desc_get_last_msdu = ath11k_hw_ipq8074_rx_desc_get_last_msdu,
+       .rx_desc_get_l3_pad_bytes = ath11k_hw_ipq8074_rx_desc_get_l3_pad_bytes,
+       .rx_desc_get_hdr_status = ath11k_hw_ipq8074_rx_desc_get_hdr_status,
+       .rx_desc_encrypt_valid = ath11k_hw_ipq8074_rx_desc_encrypt_valid,
+       .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type,
+       .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type,
+       .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl,
+       .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld,
+       .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid,
+       .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no,
+       .rx_desc_get_msdu_len = ath11k_hw_ipq8074_rx_desc_get_msdu_len,
+       .rx_desc_get_msdu_sgi = ath11k_hw_ipq8074_rx_desc_get_msdu_sgi,
+       .rx_desc_get_msdu_rate_mcs = ath11k_hw_ipq8074_rx_desc_get_msdu_rate_mcs,
+       .rx_desc_get_msdu_rx_bw = ath11k_hw_ipq8074_rx_desc_get_msdu_rx_bw,
+       .rx_desc_get_msdu_freq = ath11k_hw_ipq8074_rx_desc_get_msdu_freq,
+       .rx_desc_get_msdu_pkt_type = ath11k_hw_ipq8074_rx_desc_get_msdu_pkt_type,
+       .rx_desc_get_msdu_nss = ath11k_hw_ipq8074_rx_desc_get_msdu_nss,
+       .rx_desc_get_mpdu_tid = ath11k_hw_ipq8074_rx_desc_get_mpdu_tid,
+       .rx_desc_get_mpdu_peer_id = ath11k_hw_ipq8074_rx_desc_get_mpdu_peer_id,
+       .rx_desc_copy_attn_end_tlv = ath11k_hw_ipq8074_rx_desc_copy_attn_end,
+       .rx_desc_get_mpdu_start_tag = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_tag,
+       .rx_desc_get_mpdu_ppdu_id = ath11k_hw_ipq8074_rx_desc_get_mpdu_ppdu_id,
+       .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len,
+       .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention,
+       .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload,
+};
+
+const struct ath11k_hw_ops qcn9074_ops = {
+       .get_hw_mac_from_pdev_id = ath11k_hw_ipq6018_mac_from_pdev_id,
+       .wmi_init_config = ath11k_init_wmi_config_ipq8074,
+       .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_ipq8074,
+       .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_ipq8074,
+       .tx_mesh_enable = ath11k_hw_qcn9074_tx_mesh_enable,
+       .rx_desc_get_first_msdu = ath11k_hw_qcn9074_rx_desc_get_first_msdu,
+       .rx_desc_get_last_msdu = ath11k_hw_qcn9074_rx_desc_get_last_msdu,
+       .rx_desc_get_l3_pad_bytes = ath11k_hw_qcn9074_rx_desc_get_l3_pad_bytes,
+       .rx_desc_get_hdr_status = ath11k_hw_qcn9074_rx_desc_get_hdr_status,
+       .rx_desc_encrypt_valid = ath11k_hw_qcn9074_rx_desc_encrypt_valid,
+       .rx_desc_get_encrypt_type = ath11k_hw_qcn9074_rx_desc_get_encrypt_type,
+       .rx_desc_get_decap_type = ath11k_hw_qcn9074_rx_desc_get_decap_type,
+       .rx_desc_get_mesh_ctl = ath11k_hw_qcn9074_rx_desc_get_mesh_ctl,
+       .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_qcn9074_rx_desc_get_mpdu_seq_ctl_vld,
+       .rx_desc_get_mpdu_fc_valid = ath11k_hw_qcn9074_rx_desc_get_mpdu_fc_valid,
+       .rx_desc_get_mpdu_start_seq_no = ath11k_hw_qcn9074_rx_desc_get_mpdu_start_seq_no,
+       .rx_desc_get_msdu_len = ath11k_hw_qcn9074_rx_desc_get_msdu_len,
+       .rx_desc_get_msdu_sgi = ath11k_hw_qcn9074_rx_desc_get_msdu_sgi,
+       .rx_desc_get_msdu_rate_mcs = ath11k_hw_qcn9074_rx_desc_get_msdu_rate_mcs,
+       .rx_desc_get_msdu_rx_bw = ath11k_hw_qcn9074_rx_desc_get_msdu_rx_bw,
+       .rx_desc_get_msdu_freq = ath11k_hw_qcn9074_rx_desc_get_msdu_freq,
+       .rx_desc_get_msdu_pkt_type = ath11k_hw_qcn9074_rx_desc_get_msdu_pkt_type,
+       .rx_desc_get_msdu_nss = ath11k_hw_qcn9074_rx_desc_get_msdu_nss,
+       .rx_desc_get_mpdu_tid = ath11k_hw_qcn9074_rx_desc_get_mpdu_tid,
+       .rx_desc_get_mpdu_peer_id = ath11k_hw_qcn9074_rx_desc_get_mpdu_peer_id,
+       .rx_desc_copy_attn_end_tlv = ath11k_hw_qcn9074_rx_desc_copy_attn_end,
+       .rx_desc_get_mpdu_start_tag = ath11k_hw_qcn9074_rx_desc_get_mpdu_start_tag,
+       .rx_desc_get_mpdu_ppdu_id = ath11k_hw_qcn9074_rx_desc_get_mpdu_ppdu_id,
+       .rx_desc_set_msdu_len = ath11k_hw_qcn9074_rx_desc_set_msdu_len,
+       .rx_desc_get_attention = ath11k_hw_qcn9074_rx_desc_get_attention,
+       .rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload,
 };
 
 #define ATH11K_TX_RING_MASK_0 0x1
@@ -792,6 +1241,241 @@ const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_qca6390[] = {
        },
 };
 
+/* Target firmware's Copy Engine configuration. */
+const struct ce_pipe_config ath11k_target_ce_config_wlan_qcn9074[] = {
+       /* CE0: host->target HTC control and raw streams */
+       {
+               .pipenum = __cpu_to_le32(0),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE1: target->host HTT + HTC control */
+       {
+               .pipenum = __cpu_to_le32(1),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE2: target->host WMI */
+       {
+               .pipenum = __cpu_to_le32(2),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE3: host->target WMI */
+       {
+               .pipenum = __cpu_to_le32(3),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE4: host->target HTT */
+       {
+               .pipenum = __cpu_to_le32(4),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(256),
+               .nbytes_max = __cpu_to_le32(256),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE5: target->host Pktlog */
+       {
+               .pipenum = __cpu_to_le32(5),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE6: Reserved for target autonomous hif_memcpy */
+       {
+               .pipenum = __cpu_to_le32(6),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(16384),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE7 used only by Host */
+       {
+               .pipenum = __cpu_to_le32(7),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT_H2H),
+               .nentries = __cpu_to_le32(0),
+               .nbytes_max = __cpu_to_le32(0),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE8 target->host used only by IPA */
+       {
+               .pipenum = __cpu_to_le32(8),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(16384),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+       /* CE 9, 10, 11 are used by MHI driver */
+};
+
+/* Map from service/endpoint to Copy Engine.
+ * This table is derived from the CE_PCI TABLE, above.
+ * It is passed to the Target at startup for use by firmware.
+ */
+const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_qcn9074[] = {
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(0),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(1),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(0),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(1),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(4),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(1),
+       },
+       {
+               __cpu_to_le32(ATH11K_HTC_SVC_ID_PKT_LOG),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(5),
+       },
+
+       /* (Additions here) */
+
+       { /* must be last */
+               __cpu_to_le32(0),
+               __cpu_to_le32(0),
+               __cpu_to_le32(0),
+       },
+};
+
+const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074 = {
+       .tx  = {
+               ATH11K_TX_RING_MASK_0,
+               ATH11K_TX_RING_MASK_1,
+               ATH11K_TX_RING_MASK_2,
+       },
+       .rx_mon_status = {
+               0, 0, 0,
+               ATH11K_RX_MON_STATUS_RING_MASK_0,
+               ATH11K_RX_MON_STATUS_RING_MASK_1,
+               ATH11K_RX_MON_STATUS_RING_MASK_2,
+       },
+       .rx = {
+               0, 0, 0, 0,
+               ATH11K_RX_RING_MASK_0,
+               ATH11K_RX_RING_MASK_1,
+               ATH11K_RX_RING_MASK_2,
+               ATH11K_RX_RING_MASK_3,
+       },
+       .rx_err = {
+               0, 0, 0,
+               ATH11K_RX_ERR_RING_MASK_0,
+       },
+       .rx_wbm_rel = {
+               0, 0, 0,
+               ATH11K_RX_WBM_REL_RING_MASK_0,
+       },
+       .reo_status = {
+               0, 0, 0,
+               ATH11K_REO_STATUS_RING_MASK_0,
+       },
+       .rxdma2host = {
+               0, 0, 0,
+               ATH11K_RXDMA2HOST_RING_MASK_0,
+       },
+       .host2rxdma = {
+               0, 0, 0,
+               ATH11K_HOST2RXDMA_RING_MASK_0,
+       },
+};
+
 const struct ath11k_hw_regs ipq8074_regs = {
        /* SW2TCL(x) R0 ring configuration address */
        .hal_tcl1_ring_base_lsb = 0x00000510,
@@ -841,6 +1525,26 @@ const struct ath11k_hw_regs ipq8074_regs = {
        .hal_reo_status_ring_base_lsb = 0x00000504,
        .hal_reo_status_hp = 0x00003070,
 
+       /* WCSS relative address */
+       .hal_seq_wcss_umac_ce0_src_reg = 0x00a00000,
+       .hal_seq_wcss_umac_ce0_dst_reg = 0x00a01000,
+       .hal_seq_wcss_umac_ce1_src_reg = 0x00a02000,
+       .hal_seq_wcss_umac_ce1_dst_reg = 0x00a03000,
+
+       /* WBM Idle address */
+       .hal_wbm_idle_link_ring_base_lsb = 0x00000860,
+       .hal_wbm_idle_link_ring_misc = 0x00000870,
+
+       /* SW2WBM release address */
+       .hal_wbm_release_ring_base_lsb = 0x000001d8,
+
+       /* WBM2SW release address */
+       .hal_wbm0_release_ring_base_lsb = 0x00000910,
+       .hal_wbm1_release_ring_base_lsb = 0x00000968,
+
+       /* PCIe base address */
+       .pcie_qserdes_sysclk_en_sel = 0x0,
+       .pcie_pcs_osc_dtct_config_base = 0x0,
 };
 
 const struct ath11k_hw_regs qca6390_regs = {
@@ -891,4 +1595,96 @@ const struct ath11k_hw_regs qca6390_regs = {
        /* REO status address */
        .hal_reo_status_ring_base_lsb = 0x000004ac,
        .hal_reo_status_hp = 0x00003068,
+
+       /* WCSS relative address */
+       .hal_seq_wcss_umac_ce0_src_reg = 0x00a00000,
+       .hal_seq_wcss_umac_ce0_dst_reg = 0x00a01000,
+       .hal_seq_wcss_umac_ce1_src_reg = 0x00a02000,
+       .hal_seq_wcss_umac_ce1_dst_reg = 0x00a03000,
+
+       /* WBM Idle address */
+       .hal_wbm_idle_link_ring_base_lsb = 0x00000860,
+       .hal_wbm_idle_link_ring_misc = 0x00000870,
+
+       /* SW2WBM release address */
+       .hal_wbm_release_ring_base_lsb = 0x000001d8,
+
+       /* WBM2SW release address */
+       .hal_wbm0_release_ring_base_lsb = 0x00000910,
+       .hal_wbm1_release_ring_base_lsb = 0x00000968,
+
+       /* PCIe base address */
+       .pcie_qserdes_sysclk_en_sel = 0x01e0c0ac,
+       .pcie_pcs_osc_dtct_config_base = 0x01e0c628,
+};
+
+const struct ath11k_hw_regs qcn9074_regs = {
+       /* SW2TCL(x) R0 ring configuration address */
+       .hal_tcl1_ring_base_lsb = 0x000004f0,
+       .hal_tcl1_ring_base_msb = 0x000004f4,
+       .hal_tcl1_ring_id = 0x000004f8,
+       .hal_tcl1_ring_misc = 0x00000500,
+       .hal_tcl1_ring_tp_addr_lsb = 0x0000050c,
+       .hal_tcl1_ring_tp_addr_msb = 0x00000510,
+       .hal_tcl1_ring_consumer_int_setup_ix0 = 0x00000520,
+       .hal_tcl1_ring_consumer_int_setup_ix1 = 0x00000524,
+       .hal_tcl1_ring_msi1_base_lsb = 0x00000538,
+       .hal_tcl1_ring_msi1_base_msb = 0x0000053c,
+       .hal_tcl1_ring_msi1_data = 0x00000540,
+       .hal_tcl2_ring_base_lsb = 0x00000548,
+       .hal_tcl_ring_base_lsb = 0x000005f8,
+
+       /* TCL STATUS ring address */
+       .hal_tcl_status_ring_base_lsb = 0x00000700,
+
+       /* REO2SW(x) R0 ring configuration address */
+       .hal_reo1_ring_base_lsb = 0x0000029c,
+       .hal_reo1_ring_base_msb = 0x000002a0,
+       .hal_reo1_ring_id = 0x000002a4,
+       .hal_reo1_ring_misc = 0x000002ac,
+       .hal_reo1_ring_hp_addr_lsb = 0x000002b0,
+       .hal_reo1_ring_hp_addr_msb = 0x000002b4,
+       .hal_reo1_ring_producer_int_setup = 0x000002c0,
+       .hal_reo1_ring_msi1_base_lsb = 0x000002e4,
+       .hal_reo1_ring_msi1_base_msb = 0x000002e8,
+       .hal_reo1_ring_msi1_data = 0x000002ec,
+       .hal_reo2_ring_base_lsb = 0x000002f4,
+       .hal_reo1_aging_thresh_ix_0 = 0x00000564,
+       .hal_reo1_aging_thresh_ix_1 = 0x00000568,
+       .hal_reo1_aging_thresh_ix_2 = 0x0000056c,
+       .hal_reo1_aging_thresh_ix_3 = 0x00000570,
+
+       /* REO2SW(x) R2 ring pointers (head/tail) address */
+       .hal_reo1_ring_hp = 0x00003038,
+       .hal_reo1_ring_tp = 0x0000303c,
+       .hal_reo2_ring_hp = 0x00003040,
+
+       /* REO2TCL R0 ring configuration address */
+       .hal_reo_tcl_ring_base_lsb = 0x000003fc,
+       .hal_reo_tcl_ring_hp = 0x00003058,
+
+       /* REO status address */
+       .hal_reo_status_ring_base_lsb = 0x00000504,
+       .hal_reo_status_hp = 0x00003070,
+
+       /* WCSS relative address */
+       .hal_seq_wcss_umac_ce0_src_reg = 0x01b80000,
+       .hal_seq_wcss_umac_ce0_dst_reg = 0x01b81000,
+       .hal_seq_wcss_umac_ce1_src_reg = 0x01b82000,
+       .hal_seq_wcss_umac_ce1_dst_reg = 0x01b83000,
+
+       /* WBM Idle address */
+       .hal_wbm_idle_link_ring_base_lsb = 0x00000874,
+       .hal_wbm_idle_link_ring_misc = 0x00000884,
+
+       /* SW2WBM release address */
+       .hal_wbm_release_ring_base_lsb = 0x000001ec,
+
+       /* WBM2SW release address */
+       .hal_wbm0_release_ring_base_lsb = 0x00000924,
+       .hal_wbm1_release_ring_base_lsb = 0x0000097c,
+
+       /* PCIe base address */
+       .pcie_qserdes_sysclk_en_sel = 0x01e0e0a8,
+       .pcie_pcs_osc_dtct_config_base = 0x01e0f45c,
 };
index 8af0034..c81a632 100644 (file)
@@ -105,6 +105,9 @@ enum ath11k_bus {
 
 #define ATH11K_EXT_IRQ_GRP_NUM_MAX 11
 
+struct hal_rx_desc;
+struct hal_tcl_data_cmd;
+
 struct ath11k_hw_ring_mask {
        u8 tx[ATH11K_EXT_IRQ_GRP_NUM_MAX];
        u8 rx_mon_status[ATH11K_EXT_IRQ_GRP_NUM_MAX];
@@ -134,6 +137,7 @@ struct ath11k_hw_params {
        bool internal_sleep_clock;
 
        const struct ath11k_hw_regs *regs;
+       u32 qmi_service_ins_id;
        const struct ce_attr *host_ce_config;
        u32 ce_count;
        const struct ce_pipe_config *target_ce_config;
@@ -157,6 +161,7 @@ struct ath11k_hw_params {
        bool idle_ps;
        bool cold_boot_calib;
        bool supports_suspend;
+       u32 hal_desc_sz;
 };
 
 struct ath11k_hw_ops {
@@ -165,14 +170,45 @@ struct ath11k_hw_ops {
                                struct target_resource_config *config);
        int (*mac_id_to_pdev_id)(struct ath11k_hw_params *hw, int mac_id);
        int (*mac_id_to_srng_id)(struct ath11k_hw_params *hw, int mac_id);
+       void (*tx_mesh_enable)(struct ath11k_base *ab,
+                              struct hal_tcl_data_cmd *tcl_cmd);
+       bool (*rx_desc_get_first_msdu)(struct hal_rx_desc *desc);
+       bool (*rx_desc_get_last_msdu)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_l3_pad_bytes)(struct hal_rx_desc *desc);
+       u8 *(*rx_desc_get_hdr_status)(struct hal_rx_desc *desc);
+       bool (*rx_desc_encrypt_valid)(struct hal_rx_desc *desc);
+       u32 (*rx_desc_get_encrypt_type)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_decap_type)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_mesh_ctl)(struct hal_rx_desc *desc);
+       bool (*rx_desc_get_mpdu_seq_ctl_vld)(struct hal_rx_desc *desc);
+       bool (*rx_desc_get_mpdu_fc_valid)(struct hal_rx_desc *desc);
+       u16 (*rx_desc_get_mpdu_start_seq_no)(struct hal_rx_desc *desc);
+       u16 (*rx_desc_get_msdu_len)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_msdu_sgi)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_msdu_rate_mcs)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_msdu_rx_bw)(struct hal_rx_desc *desc);
+       u32 (*rx_desc_get_msdu_freq)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_msdu_pkt_type)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_msdu_nss)(struct hal_rx_desc *desc);
+       u8 (*rx_desc_get_mpdu_tid)(struct hal_rx_desc *desc);
+       u16 (*rx_desc_get_mpdu_peer_id)(struct hal_rx_desc *desc);
+       void (*rx_desc_copy_attn_end_tlv)(struct hal_rx_desc *fdesc,
+                                         struct hal_rx_desc *ldesc);
+       u32 (*rx_desc_get_mpdu_start_tag)(struct hal_rx_desc *desc);
+       u32 (*rx_desc_get_mpdu_ppdu_id)(struct hal_rx_desc *desc);
+       void (*rx_desc_set_msdu_len)(struct hal_rx_desc *desc, u16 len);
+       struct rx_attention *(*rx_desc_get_attention)(struct hal_rx_desc *desc);
+       u8 *(*rx_desc_get_msdu_payload)(struct hal_rx_desc *desc);
 };
 
 extern const struct ath11k_hw_ops ipq8074_ops;
 extern const struct ath11k_hw_ops ipq6018_ops;
 extern const struct ath11k_hw_ops qca6390_ops;
+extern const struct ath11k_hw_ops qcn9074_ops;
 
 extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074;
 extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390;
+extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074;
 
 static inline
 int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw,
@@ -261,9 +297,26 @@ struct ath11k_hw_regs {
 
        u32 hal_reo_status_ring_base_lsb;
        u32 hal_reo_status_hp;
+
+       u32 hal_seq_wcss_umac_ce0_src_reg;
+       u32 hal_seq_wcss_umac_ce0_dst_reg;
+       u32 hal_seq_wcss_umac_ce1_src_reg;
+       u32 hal_seq_wcss_umac_ce1_dst_reg;
+
+       u32 hal_wbm_idle_link_ring_base_lsb;
+       u32 hal_wbm_idle_link_ring_misc;
+
+       u32 hal_wbm_release_ring_base_lsb;
+
+       u32 hal_wbm0_release_ring_base_lsb;
+       u32 hal_wbm1_release_ring_base_lsb;
+
+       u32 pcie_qserdes_sysclk_en_sel;
+       u32 pcie_pcs_osc_dtct_config_base;
 };
 
 extern const struct ath11k_hw_regs ipq8074_regs;
 extern const struct ath11k_hw_regs qca6390_regs;
+extern const struct ath11k_hw_regs qcn9074_regs;
 
 #endif
index faa2e67..8719e85 100644 (file)
@@ -829,6 +829,75 @@ static void ath11k_control_beaconing(struct ath11k_vif *arvif,
        ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
 }
 
+static void ath11k_mac_handle_beacon_iter(void *data, u8 *mac,
+                                         struct ieee80211_vif *vif)
+{
+       struct sk_buff *skb = data;
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+
+       if (vif->type != NL80211_IFTYPE_STATION)
+               return;
+
+       if (!ether_addr_equal(mgmt->bssid, vif->bss_conf.bssid))
+               return;
+
+       cancel_delayed_work(&arvif->connection_loss_work);
+}
+
+void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb)
+{
+       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  ath11k_mac_handle_beacon_iter,
+                                                  skb);
+}
+
+static void ath11k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
+                                              struct ieee80211_vif *vif)
+{
+       u32 *vdev_id = data;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct ath11k *ar = arvif->ar;
+       struct ieee80211_hw *hw = ar->hw;
+
+       if (arvif->vdev_id != *vdev_id)
+               return;
+
+       if (!arvif->is_up)
+               return;
+
+       ieee80211_beacon_loss(vif);
+
+       /* Firmware doesn't report beacon loss events repeatedly. If AP probe
+        * (done by mac80211) succeeds but beacons do not resume then it
+        * doesn't make sense to continue operation. Queue connection loss work
+        * which can be cancelled when beacon is received.
+        */
+       ieee80211_queue_delayed_work(hw, &arvif->connection_loss_work,
+                                    ATH11K_CONNECTION_LOSS_HZ);
+}
+
+void ath11k_mac_handle_beacon_miss(struct ath11k *ar, u32 vdev_id)
+{
+       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  ath11k_mac_handle_beacon_miss_iter,
+                                                  &vdev_id);
+}
+
+static void ath11k_mac_vif_sta_connection_loss_work(struct work_struct *work)
+{
+       struct ath11k_vif *arvif = container_of(work, struct ath11k_vif,
+                                               connection_loss_work.work);
+       struct ieee80211_vif *vif = arvif->vif;
+
+       if (!arvif->is_up)
+               return;
+
+       ieee80211_connection_loss(vif);
+}
+
 static void ath11k_peer_assoc_h_basic(struct ath11k *ar,
                                      struct ieee80211_vif *vif,
                                      struct ieee80211_sta *sta,
@@ -1760,7 +1829,7 @@ static void ath11k_bss_disassoc(struct ieee80211_hw *hw,
 
        arvif->is_up = false;
 
-       /* TODO: cancel connection_loss_work */
+       cancel_delayed_work_sync(&arvif->connection_loss_work);
 }
 
 static u32 ath11k_mac_get_rate_hw_value(int bitrate)
@@ -3919,8 +3988,6 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar,
 
                he_cap_elem->phy_cap_info[5] &=
                        ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
-               he_cap_elem->phy_cap_info[5] &=
-                       ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK;
                he_cap_elem->phy_cap_info[5] |= ar->num_tx_chains - 1;
 
                switch (i) {
@@ -4213,7 +4280,7 @@ static int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb,
                return -ENOSPC;
        }
 
-       if (skb_queue_len(q) == ATH11K_TX_MGMT_NUM_PENDING_MAX) {
+       if (skb_queue_len_lockless(q) >= ATH11K_TX_MGMT_NUM_PENDING_MAX) {
                ath11k_warn(ar->ab, "mgmt tx queue is full\n");
                return -ENOSPC;
        }
@@ -4617,10 +4684,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
        arvif->vif = vif;
 
        INIT_LIST_HEAD(&arvif->list);
-
-       /* Should we initialize any worker to handle connection loss indication
-        * from firmware in sta mode?
-        */
+       INIT_DELAYED_WORK(&arvif->connection_loss_work,
+                         ath11k_mac_vif_sta_connection_loss_work);
 
        for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
                arvif->bitrate_mask.control[i].legacy = 0xffffffff;
@@ -4829,6 +4894,8 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
        int ret;
        int i;
 
+       cancel_delayed_work_sync(&arvif->connection_loss_work);
+
        mutex_lock(&ar->conf_mutex);
 
        ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
@@ -5096,13 +5163,15 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
                arg.channel.chan_radar =
                        !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
 
+               arg.channel.freq2_radar =
+                       !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
+
                arg.channel.passive = arg.channel.chan_radar;
 
                spin_lock_bh(&ab->base_lock);
                arg.regdomain = ar->ab->dfs_region;
                spin_unlock_bh(&ab->base_lock);
 
-               /* TODO: Notify if secondary 80Mhz also needs radar detection */
                if (he_support) {
                        ret = ath11k_set_he_mu_sounding_mode(ar, arvif);
                        if (ret) {
@@ -6082,6 +6151,7 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw,
 
        /* TODO: Use real NF instead of default one. */
        sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR;
+       sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
 }
 
 static const struct ieee80211_ops ath11k_ops = {
index 4555779..4bc59bd 100644 (file)
@@ -150,4 +150,6 @@ int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
 u8 ath11k_mac_bw_to_mac80211_bw(u8 bw);
 enum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw bw);
 enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher);
+void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb);
+void ath11k_mac_handle_beacon_miss(struct ath11k *ar, u32 vdev_id);
 #endif
index 09858e5..626764d 100644 (file)
@@ -7,10 +7,11 @@
 #include "core.h"
 #include "debug.h"
 #include "mhi.h"
+#include "pci.h"
 
 #define MHI_TIMEOUT_DEFAULT_MS 90000
 
-static struct mhi_channel_config ath11k_mhi_channels[] = {
+static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
        {
                .num = 0,
                .name = "LOOPBACK",
@@ -69,7 +70,7 @@ static struct mhi_channel_config ath11k_mhi_channels[] = {
        },
 };
 
-static struct mhi_event_config ath11k_mhi_events[] = {
+static struct mhi_event_config ath11k_mhi_events_qca6390[] = {
        {
                .num_elements = 32,
                .irq_moderation_ms = 0,
@@ -92,15 +93,108 @@ static struct mhi_event_config ath11k_mhi_events[] = {
        },
 };
 
-static struct mhi_controller_config ath11k_mhi_config = {
+static struct mhi_controller_config ath11k_mhi_config_qca6390 = {
        .max_channels = 128,
        .timeout_ms = 2000,
        .use_bounce_buf = false,
        .buf_len = 0,
-       .num_channels = ARRAY_SIZE(ath11k_mhi_channels),
-       .ch_cfg = ath11k_mhi_channels,
-       .num_events = ARRAY_SIZE(ath11k_mhi_events),
-       .event_cfg = ath11k_mhi_events,
+       .num_channels = ARRAY_SIZE(ath11k_mhi_channels_qca6390),
+       .ch_cfg = ath11k_mhi_channels_qca6390,
+       .num_events = ARRAY_SIZE(ath11k_mhi_events_qca6390),
+       .event_cfg = ath11k_mhi_events_qca6390,
+};
+
+static struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
+       {
+               .num = 0,
+               .name = "LOOPBACK",
+               .num_elements = 32,
+               .event_ring = 1,
+               .dir = DMA_TO_DEVICE,
+               .ee_mask = 0x14,
+               .pollcfg = 0,
+               .doorbell = MHI_DB_BRST_DISABLE,
+               .lpm_notify = false,
+               .offload_channel = false,
+               .doorbell_mode_switch = false,
+               .auto_queue = false,
+       },
+       {
+               .num = 1,
+               .name = "LOOPBACK",
+               .num_elements = 32,
+               .event_ring = 1,
+               .dir = DMA_FROM_DEVICE,
+               .ee_mask = 0x14,
+               .pollcfg = 0,
+               .doorbell = MHI_DB_BRST_DISABLE,
+               .lpm_notify = false,
+               .offload_channel = false,
+               .doorbell_mode_switch = false,
+               .auto_queue = false,
+       },
+       {
+               .num = 20,
+               .name = "IPCR",
+               .num_elements = 32,
+               .event_ring = 1,
+               .dir = DMA_TO_DEVICE,
+               .ee_mask = 0x14,
+               .pollcfg = 0,
+               .doorbell = MHI_DB_BRST_DISABLE,
+               .lpm_notify = false,
+               .offload_channel = false,
+               .doorbell_mode_switch = false,
+               .auto_queue = false,
+       },
+       {
+               .num = 21,
+               .name = "IPCR",
+               .num_elements = 32,
+               .event_ring = 1,
+               .dir = DMA_FROM_DEVICE,
+               .ee_mask = 0x14,
+               .pollcfg = 0,
+               .doorbell = MHI_DB_BRST_DISABLE,
+               .lpm_notify = false,
+               .offload_channel = false,
+               .doorbell_mode_switch = false,
+               .auto_queue = true,
+       },
+};
+
+static struct mhi_event_config ath11k_mhi_events_qcn9074[] = {
+       {
+               .num_elements = 32,
+               .irq_moderation_ms = 0,
+               .irq = 1,
+               .data_type = MHI_ER_CTRL,
+               .mode = MHI_DB_BRST_DISABLE,
+               .hardware_event = false,
+               .client_managed = false,
+               .offload_channel = false,
+       },
+       {
+               .num_elements = 256,
+               .irq_moderation_ms = 1,
+               .irq = 2,
+               .mode = MHI_DB_BRST_DISABLE,
+               .priority = 1,
+               .hardware_event = false,
+               .client_managed = false,
+               .offload_channel = false,
+       },
+};
+
+static struct mhi_controller_config ath11k_mhi_config_qcn9074 = {
+       .max_channels = 30,
+       .timeout_ms = 10000,
+       .use_bounce_buf = false,
+       .buf_len = 0,
+       .num_channels = ARRAY_SIZE(ath11k_mhi_channels_qcn9074),
+       .ch_cfg = ath11k_mhi_channels_qcn9074,
+       .num_events = ARRAY_SIZE(ath11k_mhi_events_qcn9074),
+       .event_cfg = ath11k_mhi_events_qcn9074,
 };
 
 void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab)
@@ -221,6 +315,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
 {
        struct ath11k_base *ab = ab_pci->ab;
        struct mhi_controller *mhi_ctrl;
+       struct mhi_controller_config *ath11k_mhi_config;
        int ret;
 
        mhi_ctrl = mhi_alloc_controller();
@@ -254,7 +349,12 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
        mhi_ctrl->read_reg = ath11k_mhi_op_read_reg;
        mhi_ctrl->write_reg = ath11k_mhi_op_write_reg;
 
-       ret = mhi_register_controller(mhi_ctrl, &ath11k_mhi_config);
+       if (ab->hw_rev == ATH11K_HW_QCA6390_HW20)
+               ath11k_mhi_config = &ath11k_mhi_config_qca6390;
+       else if (ab->hw_rev == ATH11K_HW_QCN9074_HW10)
+               ath11k_mhi_config = &ath11k_mhi_config_qcn9074;
+
+       ret = mhi_register_controller(mhi_ctrl, ath11k_mhi_config);
        if (ret) {
                ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret);
                mhi_free_controller(mhi_ctrl);
index d144168..0f31eb5 100644 (file)
 #define ACCESS_ALWAYS_OFF 0xFE0
 
 #define QCA6390_DEVICE_ID              0x1101
+#define QCN9074_DEVICE_ID              0x1104
 
 static const struct pci_device_id ath11k_pci_id_table[] = {
        { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
+       /* TODO: add QCN9074_DEVICE_ID) once firmware issues are resolved */
        {0}
 };
 
@@ -50,14 +52,25 @@ static const struct ath11k_bus_params ath11k_pci_bus_params = {
        .fixed_mem_region = false,
 };
 
-static const struct ath11k_msi_config msi_config = {
-       .total_vectors = 32,
-       .total_users = 4,
-       .users = (struct ath11k_msi_user[]) {
-               { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
-               { .name = "CE", .num_vectors = 10, .base_vector = 3 },
-               { .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
-               { .name = "DP", .num_vectors = 18, .base_vector = 14 },
+static const struct ath11k_msi_config ath11k_msi_config[] = {
+       {
+               .total_vectors = 32,
+               .total_users = 4,
+               .users = (struct ath11k_msi_user[]) {
+                       { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
+                       { .name = "CE", .num_vectors = 10, .base_vector = 3 },
+                       { .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
+                       { .name = "DP", .num_vectors = 18, .base_vector = 14 },
+               },
+       },
+       {
+               .total_vectors = 16,
+               .total_users = 3,
+               .users = (struct ath11k_msi_user[]) {
+                       { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
+                       { .name = "CE", .num_vectors = 5, .base_vector = 3 },
+                       { .name = "DP", .num_vectors = 8, .base_vector = 8 },
+               },
        },
 };
 
@@ -131,9 +144,38 @@ static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offse
        }
 }
 
+static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
+{
+       u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
+       u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
+       u32 window;
+
+       window = (umac_window << 12) | (ce_window << 6);
+
+       iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS);
+}
+
+static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab,
+                                             u32 offset)
+{
+       u32 window_start;
+
+       /* If offset lies within DP register range, use 3rd window */
+       if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)
+               window_start = 3 * WINDOW_START;
+       /* If offset lies within CE register range, use 2nd window */
+       else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)
+               window_start = 2 * WINDOW_START;
+       else
+               window_start = WINDOW_START;
+
+       return window_start;
+}
+
 void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
 {
        struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+       u32 window_start;
 
        /* for offset beyond BAR + 4K - 32, may
         * need to wakeup MHI to access.
@@ -145,10 +187,21 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
        if (offset < WINDOW_START) {
                iowrite32(value, ab->mem  + offset);
        } else {
-               spin_lock_bh(&ab_pci->window_lock);
-               ath11k_pci_select_window(ab_pci, offset);
-               iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
-               spin_unlock_bh(&ab_pci->window_lock);
+               if (ab->bus_params.static_window_map)
+                       window_start = ath11k_pci_get_window_start(ab, offset);
+               else
+                       window_start = WINDOW_START;
+
+               if (window_start == WINDOW_START) {
+                       spin_lock_bh(&ab_pci->window_lock);
+                       ath11k_pci_select_window(ab_pci, offset);
+                       iowrite32(value, ab->mem + window_start +
+                                 (offset & WINDOW_RANGE_MASK));
+                       spin_unlock_bh(&ab_pci->window_lock);
+               } else {
+                       iowrite32(value, ab->mem + window_start +
+                                 (offset & WINDOW_RANGE_MASK));
+               }
        }
 
        if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
@@ -159,7 +212,7 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
 u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
 {
        struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
-       u32 val;
+       u32 val, window_start;
 
        /* for offset beyond BAR + 4K - 32, may
         * need to wakeup MHI to access.
@@ -171,10 +224,21 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
        if (offset < WINDOW_START) {
                val = ioread32(ab->mem + offset);
        } else {
-               spin_lock_bh(&ab_pci->window_lock);
-               ath11k_pci_select_window(ab_pci, offset);
-               val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
-               spin_unlock_bh(&ab_pci->window_lock);
+               if (ab->bus_params.static_window_map)
+                       window_start = ath11k_pci_get_window_start(ab, offset);
+               else
+                       window_start = WINDOW_START;
+
+               if (window_start == WINDOW_START) {
+                       spin_lock_bh(&ab_pci->window_lock);
+                       ath11k_pci_select_window(ab_pci, offset);
+                       val = ioread32(ab->mem + window_start +
+                                      (offset & WINDOW_RANGE_MASK));
+                       spin_unlock_bh(&ab_pci->window_lock);
+               } else {
+                       val = ioread32(ab->mem + window_start +
+                                      (offset & WINDOW_RANGE_MASK));
+               }
        }
 
        if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
@@ -271,7 +335,7 @@ static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
        int ret;
 
        ret = ath11k_pci_set_link_reg(ab,
-                                     PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG,
+                                     PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
                                      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
                                      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
        if (ret) {
@@ -280,27 +344,27 @@ static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
        }
 
        ret = ath11k_pci_set_link_reg(ab,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
+                                     PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
+                                     PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
+                                     PCIE_PCS_OSC_DTCT_CONFIG_MSK);
        if (ret) {
                ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
                return ret;
        }
 
        ret = ath11k_pci_set_link_reg(ab,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
+                                     PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
+                                     PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
+                                     PCIE_PCS_OSC_DTCT_CONFIG_MSK);
        if (ret) {
                ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
                return ret;
        }
 
        ret = ath11k_pci_set_link_reg(ab,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL,
-                                     PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
+                                     PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
+                                     PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
+                                     PCIE_PCS_OSC_DTCT_CONFIG_MSK);
        if (ret) {
                ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
                return ret;
@@ -406,14 +470,15 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam
                                       u32 *base_vector)
 {
        struct ath11k_base *ab = ab_pci->ab;
+       const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
        int idx;
 
-       for (idx = 0; idx < msi_config.total_users; idx++) {
-               if (strcmp(user_name, msi_config.users[idx].name) == 0) {
-                       *num_vectors = msi_config.users[idx].num_vectors;
-                       *user_base_data = msi_config.users[idx].base_vector
+       for (idx = 0; idx < msi_config->total_users; idx++) {
+               if (strcmp(user_name, msi_config->users[idx].name) == 0) {
+                       *num_vectors = msi_config->users[idx].num_vectors;
+                       *user_base_data = msi_config->users[idx].base_vector
                                + ab_pci->msi_ep_base_data;
-                       *base_vector = msi_config.users[idx].base_vector;
+                       *base_vector = msi_config->users[idx].base_vector;
 
                        ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
                                   user_name, *num_vectors, *user_base_data,
@@ -428,6 +493,23 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam
        return -EINVAL;
 }
 
+static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
+                                     u32 *msi_idx)
+{
+       u32 i, msi_data_idx;
+
+       for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
+               if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
+                       continue;
+
+               if (ce_id == i)
+                       break;
+
+               msi_data_idx++;
+       }
+       *msi_idx = msi_data_idx;
+}
+
 static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
                                          int *num_vectors, u32 *user_base_data,
                                          u32 *base_vector)
@@ -521,6 +603,9 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
 {
        struct ath11k_ce_pipe *ce_pipe = arg;
 
+       /* last interrupt received for this CE */
+       ce_pipe->timestamp = jiffies;
+
        ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
        tasklet_schedule(&ce_pipe->intr_tq);
 
@@ -615,6 +700,9 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
 
        ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
 
+       /* last interrupt received for this group */
+       irq_grp->timestamp = jiffies;
+
        ath11k_pci_ext_grp_disable(irq_grp);
 
        napi_schedule(&irq_grp->napi);
@@ -625,8 +713,9 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
 static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
 {
        int i, j, ret, num_vectors = 0;
-       u32 user_base_data = 0, base_vector = 0;
+       u32 user_base_data = 0, base_vector = 0, base_idx;
 
+       base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
        ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
                                                 &num_vectors,
                                                 &user_base_data,
@@ -656,7 +745,7 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
                }
 
                irq_grp->num_irq = num_irq;
-               irq_grp->irqs[0] = base_vector + i;
+               irq_grp->irqs[0] = base_idx + i;
 
                for (j = 0; j < irq_grp->num_irq; j++) {
                        int irq_idx = irq_grp->irqs[j];
@@ -667,6 +756,8 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
 
                        ath11k_dbg(ab, ATH11K_DBG_PCI,
                                   "irq:%d group:%d\n", irq, i);
+
+                       irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
                        ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
                                          IRQF_SHARED,
                                          "DP_EXT_IRQ", irq_grp);
@@ -687,7 +778,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
 {
        struct ath11k_ce_pipe *ce_pipe;
        u32 msi_data_start;
-       u32 msi_data_count;
+       u32 msi_data_count, msi_data_idx;
        u32 msi_irq_start;
        unsigned int msi_data;
        int irq, i, ret, irq_idx;
@@ -699,14 +790,14 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
                return ret;
 
        /* Configure CE irqs */
-       for (i = 0; i < ab->hw_params.ce_count; i++) {
-               msi_data = (i % msi_data_count) + msi_irq_start;
-               irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
-               ce_pipe = &ab->ce.ce_pipe[i];
-
+       for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
                if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
                        continue;
 
+               msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
+               irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
+               ce_pipe = &ab->ce.ce_pipe[i];
+
                irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
 
                tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
@@ -721,6 +812,8 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
                }
 
                ab->irq_num[irq_idx] = irq;
+               msi_data_idx++;
+
                ath11k_pci_ce_irq_disable(ab, i);
        }
 
@@ -740,7 +833,7 @@ static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
 
        cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
        cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
-       ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390;
+       ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
 
        ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
                                    &cfg->shadow_reg_v2_len);
@@ -760,17 +853,18 @@ static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
 static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
 {
        struct ath11k_base *ab = ab_pci->ab;
+       const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
        struct msi_desc *msi_desc;
        int num_vectors;
        int ret;
 
        num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
-                                           msi_config.total_vectors,
-                                           msi_config.total_vectors,
+                                           msi_config->total_vectors,
+                                           msi_config->total_vectors,
                                            PCI_IRQ_MSI);
-       if (num_vectors != msi_config.total_vectors) {
+       if (num_vectors != msi_config->total_vectors) {
                ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
-                          msi_config.total_vectors, num_vectors);
+                          msi_config->total_vectors, num_vectors);
 
                if (num_vectors >= 0)
                        return -EINVAL;
@@ -932,6 +1026,9 @@ static int ath11k_pci_power_up(struct ath11k_base *ab)
                return ret;
        }
 
+       if (ab->bus_params.static_window_map)
+               ath11k_pci_select_static_window(ab_pci);
+
        return 0;
 }
 
@@ -1076,6 +1173,7 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
        .map_service_to_pipe = ath11k_pci_map_service_to_pipe,
        .ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
        .ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
+       .get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
 };
 
 static int ath11k_pci_probe(struct pci_dev *pdev,
@@ -1130,6 +1228,12 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
                        ret = -EOPNOTSUPP;
                        goto err_pci_free_region;
                }
+               ab_pci->msi_config = &ath11k_msi_config[0];
+               break;
+       case QCN9074_DEVICE_ID:
+               ab_pci->msi_config = &ath11k_msi_config[1];
+               ab->bus_params.static_window_map = true;
+               ab->hw_rev = ATH11K_HW_QCN9074_HW10;
                break;
        default:
                dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
index fe44d0d..f3e6458 100644 (file)
 #define PCIE_SMLH_REQ_RST_LINK_DOWN            0x2
 #define PCIE_INT_CLEAR_ALL                     0xffffffff
 
-#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG     0x01e0c0ac
+#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(x) \
+               (ab->hw_params.regs->pcie_qserdes_sysclk_en_sel)
 #define PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL     0x10
 #define PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK     0xffffffff
-#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG        0x01e0c628
-#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL        0x02
-#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG        0x01e0c62c
-#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL        0x52
-#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG        0x01e0c634
-#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL        0xff
-#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK 0x000000ff
+#define PCIE_PCS_OSC_DTCT_CONFIG1_REG(x) \
+               (ab->hw_params.regs->pcie_pcs_osc_dtct_config_base)
+#define PCIE_PCS_OSC_DTCT_CONFIG1_VAL          0x02
+#define PCIE_PCS_OSC_DTCT_CONFIG2_REG(x) \
+               (ab->hw_params.regs->pcie_pcs_osc_dtct_config_base + 0x4)
+#define PCIE_PCS_OSC_DTCT_CONFIG2_VAL          0x52
+#define PCIE_PCS_OSC_DTCT_CONFIG4_REG(x) \
+               (ab->hw_params.regs->pcie_pcs_osc_dtct_config_base + 0xc)
+#define PCIE_PCS_OSC_DTCT_CONFIG4_VAL          0xff
+#define PCIE_PCS_OSC_DTCT_CONFIG_MSK           0x000000ff
 
 #define WLAON_QFPROM_PWR_CTRL_REG              0x01f8031c
 #define QFPROM_PWR_CTRL_VDD4BLOW_MASK          0x4
@@ -73,6 +77,7 @@ struct ath11k_pci {
        char amss_path[100];
        u32 msi_ep_base_data;
        struct mhi_controller *mhi_ctrl;
+       const struct ath11k_msi_config *msi_config;
        unsigned long mhi_state;
        u32 register_window;
 
index 7968fe4..a612e27 100644 (file)
@@ -1556,6 +1556,8 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab)
                req.nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT;
        }
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi host cap request\n");
+
        ret = qmi_txn_init(&ab->qmi.handle, &txn,
                           qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp);
        if (ret < 0)
@@ -1566,7 +1568,7 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab)
                               QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_host_cap_req_msg_v01_ei, &req);
        if (ret < 0) {
-               ath11k_warn(ab, "Failed to send host capability request,err = %d\n", ret);
+               ath11k_warn(ab, "failed to send host capability request: %d\n", ret);
                goto out;
        }
 
@@ -1575,7 +1577,7 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab)
                goto out;
 
        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-               ath11k_warn(ab, "Host capability request failed, result: %d, err: %d\n",
+               ath11k_warn(ab, "host capability request failed: %d %d\n",
                            resp.resp.result, resp.resp.error);
                ret = -EINVAL;
                goto out;
@@ -1624,24 +1626,26 @@ static int ath11k_qmi_fw_ind_register_send(struct ath11k_base *ab)
        if (ret < 0)
                goto out;
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi indication register request\n");
+
        ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
                               QMI_WLANFW_IND_REGISTER_REQ_V01,
                               QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_ind_register_req_msg_v01_ei, req);
        if (ret < 0) {
-               ath11k_warn(ab, "Failed to send indication register request, err = %d\n",
+               ath11k_warn(ab, "failed to send indication register request: %d\n",
                            ret);
                goto out;
        }
 
        ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
        if (ret < 0) {
-               ath11k_warn(ab, "failed to register fw indication %d\n", ret);
+               ath11k_warn(ab, "failed to register fw indication: %d\n", ret);
                goto out;
        }
 
        if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
-               ath11k_warn(ab, "FW Ind register request failed, result: %d, err: %d\n",
+               ath11k_warn(ab, "firmware indication register request failed: %d %d\n",
                            resp->resp.result, resp->resp.error);
                ret = -EINVAL;
                goto out;
@@ -1699,19 +1703,22 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab)
        if (ret < 0)
                goto out;
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi respond memory request delayed %i\n",
+                  delayed);
+
        ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
                               QMI_WLANFW_RESPOND_MEM_REQ_V01,
                               QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_respond_mem_req_msg_v01_ei, req);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to respond memory request, err = %d\n",
+               ath11k_warn(ab, "failed to respond qmi memory request: %d\n",
                            ret);
                goto out;
        }
 
        ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed memory request, err = %d\n", ret);
+               ath11k_warn(ab, "failed to wait qmi memory request: %d\n", ret);
                goto out;
        }
 
@@ -1722,7 +1729,7 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab)
                if (delayed && resp.resp.error == 0)
                        goto out;
 
-               ath11k_warn(ab, "Respond mem req failed, result: %d, err: %d\n",
+               ath11k_warn(ab, "qmi respond memory request failed: %d %d\n",
                            resp.resp.result, resp.resp.error);
                ret = -EINVAL;
                goto out;
@@ -1765,7 +1772,7 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
                                                  &chunk->paddr,
                                                  GFP_KERNEL);
                if (!chunk->vaddr) {
-                       if (ab->qmi.mem_seg_count <= 2) {
+                       if (ab->qmi.mem_seg_count <= ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT) {
                                ath11k_dbg(ab, ATH11K_DBG_QMI,
                                           "qmi dma allocation failed (%d B type %u), will try later with small size\n",
                                            chunk->size,
@@ -1774,7 +1781,8 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
                                ab->qmi.target_mem_delayed = true;
                                return 0;
                        }
-                       ath11k_err(ab, "failed to alloc memory, size: 0x%x, type: %u\n",
+
+                       ath11k_err(ab, "failed to allocate dma memory for qmi (%d B type %u)\n",
                                   chunk->size,
                                   chunk->type);
                        return -EINVAL;
@@ -1843,24 +1851,26 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab)
        if (ret < 0)
                goto out;
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi target cap request\n");
+
        ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
                               QMI_WLANFW_CAP_REQ_V01,
                               QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_cap_req_msg_v01_ei, &req);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send target cap request, err = %d\n",
+               ath11k_warn(ab, "failed to send qmi cap request: %d\n",
                            ret);
                goto out;
        }
 
        ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed target cap request %d\n", ret);
+               ath11k_warn(ab, "failed to wait qmi cap request: %d\n", ret);
                goto out;
        }
 
        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-               ath11k_warn(ab, "qmi targetcap req failed, result: %d, err: %d\n",
+               ath11k_warn(ab, "qmi cap request failed: %d %d\n",
                            resp.resp.result, resp.resp.error);
                ret = -EINVAL;
                goto out;
@@ -1923,7 +1933,7 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type,
 
                ret = ath11k_core_fetch_bdf(ab, &bd);
                if (ret) {
-                       ath11k_warn(ab, "qmi failed to load BDF\n");
+                       ath11k_warn(ab, "failed to load board file: %d\n", ret);
                        return ret;
                }
 
@@ -1971,7 +1981,7 @@ static int ath11k_qmi_load_bdf_fixed_addr(struct ath11k_base *ab)
 
        bdf_addr = ioremap(ab->hw_params.bdf_addr, ATH11K_QMI_BDF_MAX_SIZE);
        if (!bdf_addr) {
-               ath11k_warn(ab, "qmi ioremap error for BDF\n");
+               ath11k_warn(ab, "failed ioremap for board file\n");
                ret = -EIO;
                goto out;
        }
@@ -2000,6 +2010,9 @@ static int ath11k_qmi_load_bdf_fixed_addr(struct ath11k_base *ab)
                if (ret < 0)
                        goto out_qmi_bdf;
 
+               ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download req fixed addr type %d\n",
+                          type);
+
                ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
                                       QMI_WLANFW_BDF_DOWNLOAD_REQ_V01,
                                       QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN,
@@ -2014,7 +2027,7 @@ static int ath11k_qmi_load_bdf_fixed_addr(struct ath11k_base *ab)
                        goto out_qmi_bdf;
 
                if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-                       ath11k_warn(ab, "qmi BDF download failed, result: %d, err: %d\n",
+                       ath11k_warn(ab, "board file download request failed: %d %d\n",
                                    resp.resp.result, resp.resp.error);
                        ret = -EINVAL;
                        goto out_qmi_bdf;
@@ -2047,7 +2060,7 @@ static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab)
        memset(&bd, 0, sizeof(bd));
        ret = ath11k_core_fetch_bdf(ab, &bd);
        if (ret) {
-               ath11k_warn(ab, "qmi failed to load bdf:\n");
+               ath11k_warn(ab, "failed to fetch board file: %d\n", ret);
                goto out;
        }
 
@@ -2090,6 +2103,9 @@ static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab)
                if (ret < 0)
                        goto out_qmi_bdf;
 
+               ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download request remaining %i\n",
+                          remaining);
+
                ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
                                       QMI_WLANFW_BDF_DOWNLOAD_REQ_V01,
                                       QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN,
@@ -2104,7 +2120,7 @@ static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab)
                        goto out_qmi_bdf;
 
                if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-                       ath11k_warn(ab, "qmi BDF download failed, result: %d, err: %d\n",
+                       ath11k_warn(ab, "bdf download request failed: %d %d\n",
                                    resp.resp.result, resp.resp.error);
                        ret = resp.resp.result;
                        goto out_qmi_bdf;
@@ -2200,24 +2216,26 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab)
        if (ret < 0)
                goto out;
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi m3 info req\n");
+
        ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
                               QMI_WLANFW_M3_INFO_REQ_V01,
                               QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN,
                               qmi_wlanfw_m3_info_req_msg_v01_ei, &req);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send M3 information request, err = %d\n",
+               ath11k_warn(ab, "failed to send m3 information request: %d\n",
                            ret);
                goto out;
        }
 
        ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed M3 information request %d\n", ret);
+               ath11k_warn(ab, "failed to wait m3 information request: %d\n", ret);
                goto out;
        }
 
        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-               ath11k_warn(ab, "qmi M3 info request failed, result: %d, err: %d\n",
+               ath11k_warn(ab, "m3 info request failed: %d %d\n",
                            resp.resp.result, resp.resp.error);
                ret = -EINVAL;
                goto out;
@@ -2246,12 +2264,14 @@ static int ath11k_qmi_wlanfw_mode_send(struct ath11k_base *ab,
        if (ret < 0)
                goto out;
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wlan mode req mode %d\n", mode);
+
        ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
                               QMI_WLANFW_WLAN_MODE_REQ_V01,
                               QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send mode request, mode: %d, err = %d\n",
+               ath11k_warn(ab, "failed to send wlan mode request (mode %d): %d\n",
                            mode, ret);
                goto out;
        }
@@ -2262,13 +2282,13 @@ static int ath11k_qmi_wlanfw_mode_send(struct ath11k_base *ab,
                        ath11k_warn(ab, "WLFW service is dis-connected\n");
                        return 0;
                }
-               ath11k_warn(ab, "qmi failed set mode request, mode: %d, err = %d\n",
+               ath11k_warn(ab, "failed to wait wlan mode request (mode %d): %d\n",
                            mode, ret);
                goto out;
        }
 
        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-               ath11k_warn(ab, "Mode request failed, mode: %d, result: %d err: %d\n",
+               ath11k_warn(ab, "wlan mode request failed (mode: %d): %d %d\n",
                            mode, resp.resp.result, resp.resp.error);
                ret = -EINVAL;
                goto out;
@@ -2338,24 +2358,26 @@ static int ath11k_qmi_wlanfw_wlan_cfg_send(struct ath11k_base *ab)
        if (ret < 0)
                goto out;
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wlan cfg req\n");
+
        ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
                               QMI_WLANFW_WLAN_CFG_REQ_V01,
                               QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_wlan_cfg_req_msg_v01_ei, req);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send wlan config request, err = %d\n",
+               ath11k_warn(ab, "failed to send wlan config request: %d\n",
                            ret);
                goto out;
        }
 
        ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed wlan config request, err = %d\n", ret);
+               ath11k_warn(ab, "failed to wait wlan config request: %d\n", ret);
                goto out;
        }
 
        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-               ath11k_warn(ab, "qmi wlan config request failed, result: %d, err: %d\n",
+               ath11k_warn(ab, "wlan config request failed: %d %d\n",
                            resp.resp.result, resp.resp.error);
                ret = -EINVAL;
                goto out;
@@ -2370,9 +2392,11 @@ void ath11k_qmi_firmware_stop(struct ath11k_base *ab)
 {
        int ret;
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware stop\n");
+
        ret = ath11k_qmi_wlanfw_mode_send(ab, ATH11K_FIRMWARE_MODE_OFF);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send wlan mode off\n");
+               ath11k_warn(ab, "qmi failed to send wlan mode off: %d\n", ret);
                return;
        }
 }
@@ -2382,15 +2406,17 @@ int ath11k_qmi_firmware_start(struct ath11k_base *ab,
 {
        int ret;
 
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware start\n");
+
        ret = ath11k_qmi_wlanfw_wlan_cfg_send(ab);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send wlan cfg:%d\n", ret);
+               ath11k_warn(ab, "qmi failed to send wlan cfg: %d\n", ret);
                return ret;
        }
 
        ret = ath11k_qmi_wlanfw_mode_send(ab, mode);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send wlan fw mode:%d\n", ret);
+               ath11k_warn(ab, "qmi failed to send wlan fw mode: %d\n", ret);
                return ret;
        }
 
@@ -2404,7 +2430,7 @@ static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab)
 
        ret = ath11k_qmi_wlanfw_mode_send(ab, ATH11K_FIRMWARE_MODE_COLD_BOOT);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send wlan fw mode:%d\n", ret);
+               ath11k_warn(ab, "qmi failed to send wlan fw mode: %d\n", ret);
                return ret;
        }
 
@@ -2414,7 +2440,7 @@ static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab)
                                     (ab->qmi.cal_done  == 1),
                                     ATH11K_COLD_BOOT_FW_RESET_DELAY);
        if (timeout <= 0) {
-               ath11k_warn(ab, "Coldboot Calibration failed - wait ended\n");
+               ath11k_warn(ab, "coldboot calibration timed out\n");
                return 0;
        }
 
@@ -2453,13 +2479,14 @@ static int ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi)
 
        ret = ath11k_qmi_fw_ind_register_send(ab);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send FW indication QMI:%d\n", ret);
+               ath11k_warn(ab, "failed to send qmi firmware indication: %d\n",
+                           ret);
                return ret;
        }
 
        ret = ath11k_qmi_host_cap_send(ab);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send host cap QMI:%d\n", ret);
+               ath11k_warn(ab, "failed to send qmi host cap: %d\n", ret);
                return ret;
        }
 
@@ -2473,7 +2500,7 @@ static int ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi)
 
        ret = ath11k_qmi_respond_fw_mem_request(ab);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to respond fw mem req:%d\n", ret);
+               ath11k_warn(ab, "qmi failed to respond fw mem req: %d\n", ret);
                return ret;
        }
 
@@ -2487,7 +2514,8 @@ static int ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
 
        ret = ath11k_qmi_request_target_cap(ab);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to req target capabilities:%d\n", ret);
+               ath11k_warn(ab, "failed to requeqst qmi target capabilities: %d\n",
+                           ret);
                return ret;
        }
 
@@ -2496,13 +2524,13 @@ static int ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
        else
                ret = ath11k_qmi_load_bdf_qmi(ab);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to load board data file:%d\n", ret);
+               ath11k_warn(ab, "failed to load board data file: %d\n", ret);
                return ret;
        }
 
        ret = ath11k_qmi_wlanfw_m3_info_send(ab);
        if (ret < 0) {
-               ath11k_warn(ab, "qmi failed to send m3 info req:%d\n", ret);
+               ath11k_warn(ab, "failed to send qmi m3 info req: %d\n", ret);
                return ret;
        }
 
@@ -2523,7 +2551,7 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl,
 
        if (msg->mem_seg_len == 0 ||
            msg->mem_seg_len > ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01)
-               ath11k_warn(ab, "Invalid memory segment length: %u\n",
+               ath11k_warn(ab, "invalid memory segment length: %u\n",
                            msg->mem_seg_len);
 
        ab->qmi.mem_seg_count = msg->mem_seg_len;
@@ -2538,14 +2566,14 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl,
        if (ab->bus_params.fixed_mem_region) {
                ret = ath11k_qmi_assign_target_mem_chunk(ab);
                if (ret) {
-                       ath11k_warn(ab, "qmi failed to assign target memory: %d\n",
+                       ath11k_warn(ab, "failed to assign qmi target memory: %d\n",
                                    ret);
                        return;
                }
        } else {
                ret = ath11k_qmi_alloc_target_mem_chunk(ab);
                if (ret) {
-                       ath11k_warn(ab, "qmi failed to alloc target memory: %d\n",
+                       ath11k_warn(ab, "failed to allocate qmi target memory: %d\n",
                                    ret);
                        return;
                }
@@ -2639,7 +2667,7 @@ static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
        ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)sq,
                             sizeof(*sq), 0);
        if (ret) {
-               ath11k_warn(ab, "qmi failed to connect to remote service %d\n", ret);
+               ath11k_warn(ab, "failed to connect to qmi remote service: %d\n", ret);
                return ret;
        }
 
@@ -2725,7 +2753,7 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
                case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
                        break;
                default:
-                       ath11k_warn(ab, "invalid event type: %d", event->type);
+                       ath11k_warn(ab, "invalid qmi event type: %d", event->type);
                        break;
                }
                kfree(event);
@@ -2746,7 +2774,7 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
        ret = qmi_handle_init(&ab->qmi.handle, ATH11K_QMI_RESP_LEN_MAX,
                              &ath11k_qmi_ops, ath11k_qmi_msg_handlers);
        if (ret < 0) {
-               ath11k_warn(ab, "failed to initialize qmi handle\n");
+               ath11k_warn(ab, "failed to initialize qmi handle: %d\n", ret);
                return ret;
        }
 
@@ -2765,7 +2793,7 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
                             ATH11K_QMI_WLFW_SERVICE_VERS_V01,
                             ab->qmi.service_ins_id);
        if (ret < 0) {
-               ath11k_warn(ab, "failed to add qmi lookup\n");
+               ath11k_warn(ab, "failed to add qmi lookup: %d\n", ret);
                destroy_workqueue(ab->qmi.event_wq);
                return ret;
        }
index 7bad374..3d59303 100644 (file)
 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01     0x02
 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390     0x01
 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074     0x02
+#define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9074     0x07
 #define ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01        32
 #define ATH11K_QMI_RESP_LEN_MAX                        8192
-#define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01  32
+#define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01  52
 #define ATH11K_QMI_CALDB_SIZE                  0x480000
 #define ATH11K_QMI_BDF_EXT_STR_LENGTH          0x20
+#define ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT      3
 
 #define QMI_WLFW_REQUEST_MEM_IND_V01           0x0035
 #define QMI_WLFW_FW_MEM_READY_IND_V01          0x0037
@@ -141,6 +143,7 @@ struct ath11k_qmi {
 #define QMI_IPQ8074_FW_MEM_MODE                                0xFF
 #define HOST_DDR_REGION_TYPE                           0x1
 #define BDF_MEM_REGION_TYPE                            0x2
+#define M3_DUMP_REGION_TYPE                            0x3
 #define CALDB_MEM_REGION_TYPE                          0x4
 
 struct qmi_wlanfw_host_cap_req_msg_v01 {
@@ -216,8 +219,8 @@ struct qmi_wlanfw_ind_register_resp_msg_v01 {
        u64 fw_status;
 };
 
-#define QMI_WLANFW_REQUEST_MEM_IND_MSG_V01_MAX_LEN     1124
-#define QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN     548
+#define QMI_WLANFW_REQUEST_MEM_IND_MSG_V01_MAX_LEN     1824
+#define QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN     888
 #define QMI_WLANFW_RESPOND_MEM_RESP_MSG_V01_MAX_LEN    7
 #define QMI_WLANFW_REQUEST_MEM_IND_V01                 0x0035
 #define QMI_WLANFW_RESPOND_MEM_REQ_V01                 0x0036
index 86494da..0cdb4a1 100644 (file)
@@ -414,7 +414,7 @@ struct rx_attention {
 
 #define RX_MPDU_START_RAW_MPDU                 BIT(0)
 
-struct rx_mpdu_start {
+struct rx_mpdu_start_ipq8074 {
        __le16 info0;
        __le16 phy_ppdu_id;
        __le16 ast_index;
@@ -440,6 +440,112 @@ struct rx_mpdu_start {
        __le32 raw;
 } __packed;
 
+#define RX_MPDU_START_INFO7_REO_DEST_IND               GENMASK(4, 0)
+#define RX_MPDU_START_INFO7_LMAC_PEER_ID_MSB           GENMASK(6, 5)
+#define RX_MPDU_START_INFO7_FLOW_ID_TOEPLITZ           BIT(7)
+#define RX_MPDU_START_INFO7_PKT_SEL_FP_UCAST_DATA      BIT(8)
+#define RX_MPDU_START_INFO7_PKT_SEL_FP_MCAST_DATA      BIT(9)
+#define RX_MPDU_START_INFO7_PKT_SEL_FP_CTRL_BAR                BIT(10)
+#define RX_MPDU_START_INFO7_RXDMA0_SRC_RING_SEL                GENMASK(12, 11)
+#define RX_MPDU_START_INFO7_RXDMA0_DST_RING_SEL                GENMASK(14, 13)
+
+#define RX_MPDU_START_INFO8_REO_QUEUE_DESC_HI          GENMASK(7, 0)
+#define RX_MPDU_START_INFO8_RECV_QUEUE_NUM             GENMASK(23, 8)
+#define RX_MPDU_START_INFO8_PRE_DELIM_ERR_WARN         BIT(24)
+#define RX_MPDU_START_INFO8_FIRST_DELIM_ERR            BIT(25)
+
+#define RX_MPDU_START_INFO9_EPD_EN                     BIT(0)
+#define RX_MPDU_START_INFO9_ALL_FRAME_ENCPD            BIT(1)
+#define RX_MPDU_START_INFO9_ENC_TYPE                   GENMASK(5, 2)
+#define RX_MPDU_START_INFO9_VAR_WEP_KEY_WIDTH          GENMASK(7, 6)
+#define RX_MPDU_START_INFO9_MESH_STA                   GENMASK(9, 8)
+#define RX_MPDU_START_INFO9_BSSID_HIT                  BIT(10)
+#define RX_MPDU_START_INFO9_BSSID_NUM                  GENMASK(14, 11)
+#define RX_MPDU_START_INFO9_TID                                GENMASK(18, 15)
+
+#define RX_MPDU_START_INFO10_RXPCU_MPDU_FLTR           GENMASK(1, 0)
+#define RX_MPDU_START_INFO10_SW_FRAME_GRP_ID           GENMASK(8, 2)
+#define RX_MPDU_START_INFO10_NDP_FRAME                 BIT(9)
+#define RX_MPDU_START_INFO10_PHY_ERR                   BIT(10)
+#define RX_MPDU_START_INFO10_PHY_ERR_MPDU_HDR          BIT(11)
+#define RX_MPDU_START_INFO10_PROTO_VER_ERR             BIT(12)
+#define RX_MPDU_START_INFO10_AST_LOOKUP_VALID          BIT(13)
+
+#define RX_MPDU_START_INFO11_MPDU_FCTRL_VALID          BIT(0)
+#define RX_MPDU_START_INFO11_MPDU_DUR_VALID            BIT(1)
+#define RX_MPDU_START_INFO11_MAC_ADDR1_VALID           BIT(2)
+#define RX_MPDU_START_INFO11_MAC_ADDR2_VALID           BIT(3)
+#define RX_MPDU_START_INFO11_MAC_ADDR3_VALID           BIT(4)
+#define RX_MPDU_START_INFO11_MAC_ADDR4_VALID           BIT(5)
+#define RX_MPDU_START_INFO11_MPDU_SEQ_CTRL_VALID       BIT(6)
+#define RX_MPDU_START_INFO11_MPDU_QOS_CTRL_VALID       BIT(7)
+#define RX_MPDU_START_INFO11_MPDU_HT_CTRL_VALID                BIT(8)
+#define RX_MPDU_START_INFO11_ENCRYPT_INFO_VALID                BIT(9)
+#define RX_MPDU_START_INFO11_MPDU_FRAG_NUMBER          GENMASK(13, 10)
+#define RX_MPDU_START_INFO11_MORE_FRAG_FLAG            BIT(14)
+#define RX_MPDU_START_INFO11_FROM_DS                   BIT(16)
+#define RX_MPDU_START_INFO11_TO_DS                     BIT(17)
+#define RX_MPDU_START_INFO11_ENCRYPTED                 BIT(18)
+#define RX_MPDU_START_INFO11_MPDU_RETRY                        BIT(19)
+#define RX_MPDU_START_INFO11_MPDU_SEQ_NUM              GENMASK(31, 20)
+
+#define RX_MPDU_START_INFO12_KEY_ID                    GENMASK(7, 0)
+#define RX_MPDU_START_INFO12_NEW_PEER_ENTRY            BIT(8)
+#define RX_MPDU_START_INFO12_DECRYPT_NEEDED            BIT(9)
+#define RX_MPDU_START_INFO12_DECAP_TYPE                        GENMASK(11, 10)
+#define RX_MPDU_START_INFO12_VLAN_TAG_C_PADDING                BIT(12)
+#define RX_MPDU_START_INFO12_VLAN_TAG_S_PADDING                BIT(13)
+#define RX_MPDU_START_INFO12_STRIP_VLAN_TAG_C          BIT(14)
+#define RX_MPDU_START_INFO12_STRIP_VLAN_TAG_S          BIT(15)
+#define RX_MPDU_START_INFO12_PRE_DELIM_COUNT           GENMASK(27, 16)
+#define RX_MPDU_START_INFO12_AMPDU_FLAG                        BIT(28)
+#define RX_MPDU_START_INFO12_BAR_FRAME                 BIT(29)
+#define RX_MPDU_START_INFO12_RAW_MPDU                  BIT(30)
+
+#define RX_MPDU_START_INFO13_MPDU_LEN                  GENMASK(13, 0)
+#define RX_MPDU_START_INFO13_FIRST_MPDU                        BIT(14)
+#define RX_MPDU_START_INFO13_MCAST_BCAST               BIT(15)
+#define RX_MPDU_START_INFO13_AST_IDX_NOT_FOUND         BIT(16)
+#define RX_MPDU_START_INFO13_AST_IDX_TIMEOUT           BIT(17)
+#define RX_MPDU_START_INFO13_POWER_MGMT                        BIT(18)
+#define RX_MPDU_START_INFO13_NON_QOS                   BIT(19)
+#define RX_MPDU_START_INFO13_NULL_DATA                 BIT(20)
+#define RX_MPDU_START_INFO13_MGMT_TYPE                 BIT(21)
+#define RX_MPDU_START_INFO13_CTRL_TYPE                 BIT(22)
+#define RX_MPDU_START_INFO13_MORE_DATA                 BIT(23)
+#define RX_MPDU_START_INFO13_EOSP                      BIT(24)
+#define RX_MPDU_START_INFO13_FRAGMENT                  BIT(25)
+#define RX_MPDU_START_INFO13_ORDER                     BIT(26)
+#define RX_MPDU_START_INFO13_UAPSD_TRIGGER             BIT(27)
+#define RX_MPDU_START_INFO13_ENCRYPT_REQUIRED          BIT(28)
+#define RX_MPDU_START_INFO13_DIRECTED                  BIT(29)
+#define RX_MPDU_START_INFO13_AMSDU_PRESENT             BIT(30)
+
+struct rx_mpdu_start_qcn9074 {
+       __le32 info7;
+       __le32 reo_queue_desc_lo;
+       __le32 info8;
+       __le32 pn[4];
+       __le32 info9;
+       __le32 peer_meta_data;
+       __le16 info10;
+       __le16 phy_ppdu_id;
+       __le16 ast_index;
+       __le16 sw_peer_id;
+       __le32 info11;
+       __le32 info12;
+       __le32 info13;
+       __le16 frame_ctrl;
+       __le16 duration;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       __le16 seq_ctrl;
+       u8 addr4[ETH_ALEN];
+       __le16 qos_ctrl;
+       __le32 ht_ctrl;
+} __packed;
+
 /* rx_mpdu_start
  *
  * rxpcu_mpdu_filter_in_category
@@ -672,7 +778,19 @@ enum rx_msdu_start_reception_type {
 #define RX_MSDU_START_INFO3_RECEPTION_TYPE     GENMASK(23, 21)
 #define RX_MSDU_START_INFO3_MIMO_SS_BITMAP     GENMASK(31, 24)
 
-struct rx_msdu_start {
+struct rx_msdu_start_ipq8074 {
+       __le16 info0;
+       __le16 phy_ppdu_id;
+       __le32 info1;
+       __le32 info2;
+       __le32 toeplitz_hash;
+       __le32 flow_id_toeplitz;
+       __le32 info3;
+       __le32 ppdu_start_timestamp;
+       __le32 phy_meta_data;
+} __packed;
+
+struct rx_msdu_start_qcn9074 {
        __le16 info0;
        __le16 phy_ppdu_id;
        __le32 info1;
@@ -682,6 +800,8 @@ struct rx_msdu_start {
        __le32 info3;
        __le32 ppdu_start_timestamp;
        __le32 phy_meta_data;
+       __le16 vlan_ctag_c1;
+       __le16 vlan_stag_c1;
 } __packed;
 
 /* rx_msdu_start
@@ -894,7 +1014,7 @@ struct rx_msdu_start {
 #define RX_MSDU_END_INFO5_REO_DEST_IND         GENMASK(5, 1)
 #define RX_MSDU_END_INFO5_FLOW_IDX             GENMASK(25, 6)
 
-struct rx_msdu_end {
+struct rx_msdu_end_ipq8074 {
        __le16 info0;
        __le16 phy_ppdu_id;
        __le16 ip_hdr_cksum;
@@ -917,6 +1037,58 @@ struct rx_msdu_end {
        __le16 sa_sw_peer_id;
 } __packed;
 
+#define RX_MSDU_END_MPDU_LENGTH_INFO           GENMASK(13, 0)
+
+#define RX_MSDU_END_INFO2_DA_OFFSET            GENMASK(5, 0)
+#define RX_MSDU_END_INFO2_SA_OFFSET            GENMASK(11, 6)
+#define RX_MSDU_END_INFO2_DA_OFFSET_VALID      BIT(12)
+#define RX_MSDU_END_INFO2_SA_OFFSET_VALID      BIT(13)
+#define RX_MSDU_END_INFO2_L3_TYPE              GENMASK(31, 16)
+
+#define RX_MSDU_END_INFO4_SA_IDX_TIMEOUT       BIT(0)
+#define RX_MSDU_END_INFO4_DA_IDX_TIMEOUT       BIT(1)
+#define RX_MSDU_END_INFO4_MSDU_LIMIT_ERR       BIT(2)
+#define RX_MSDU_END_INFO4_FLOW_IDX_TIMEOUT     BIT(3)
+#define RX_MSDU_END_INFO4_FLOW_IDX_INVALID     BIT(4)
+#define RX_MSDU_END_INFO4_WIFI_PARSER_ERR      BIT(5)
+#define RX_MSDU_END_INFO4_AMSDU_PARSER_ERR     BIT(6)
+#define RX_MSDU_END_INFO4_SA_IS_VALID          BIT(7)
+#define RX_MSDU_END_INFO4_DA_IS_VALID          BIT(8)
+#define RX_MSDU_END_INFO4_DA_IS_MCBC           BIT(9)
+#define RX_MSDU_END_INFO4_L3_HDR_PADDING       GENMASK(11, 10)
+#define RX_MSDU_END_INFO4_FIRST_MSDU           BIT(12)
+#define RX_MSDU_END_INFO4_LAST_MSDU            BIT(13)
+
+#define RX_MSDU_END_INFO6_AGGR_COUNT           GENMASK(7, 0)
+#define RX_MSDU_END_INFO6_FLOW_AGGR_CONTN      BIT(8)
+#define RX_MSDU_END_INFO6_FISA_TIMEOUT         BIT(9)
+
+struct rx_msdu_end_qcn9074 {
+       __le16 info0;
+       __le16 phy_ppdu_id;
+       __le16 ip_hdr_cksum;
+       __le16 mpdu_length_info;
+       __le32 info1;
+       __le32 rule_indication[2];
+       __le32 info2;
+       __le32 ipv6_options_crc;
+       __le32 tcp_seq_num;
+       __le32 tcp_ack_num;
+       __le16 info3;
+       __le16 window_size;
+       __le16 tcp_udp_cksum;
+       __le16 info4;
+       __le16 sa_idx;
+       __le16 da_idx;
+       __le32 info5;
+       __le32 fse_metadata;
+       __le16 cce_metadata;
+       __le16 sa_sw_peer_id;
+       __le32 info6;
+       __le16 cum_l4_cksum;
+       __le16 cum_ip_length;
+} __packed;
+
 /* rx_msdu_end
  *
  * rxpcu_mpdu_filter_in_category
@@ -1190,16 +1362,16 @@ struct rx_mpdu_end {
 
 #define HAL_RX_DESC_HDR_STATUS_LEN     120
 
-struct hal_rx_desc {
+struct hal_rx_desc_ipq8074 {
        __le32 msdu_end_tag;
-       struct rx_msdu_end msdu_end;
+       struct rx_msdu_end_ipq8074 msdu_end;
        __le32 rx_attn_tag;
        struct rx_attention attention;
        __le32 msdu_start_tag;
-       struct rx_msdu_start msdu_start;
+       struct rx_msdu_start_ipq8074 msdu_start;
        u8 rx_padding0[HAL_RX_DESC_PADDING0_BYTES];
        __le32 mpdu_start_tag;
-       struct rx_mpdu_start mpdu_start;
+       struct rx_mpdu_start_ipq8074 mpdu_start;
        __le32 mpdu_end_tag;
        struct rx_mpdu_end mpdu_end;
        u8 rx_padding1[HAL_RX_DESC_PADDING1_BYTES];
@@ -1209,6 +1381,32 @@ struct hal_rx_desc {
        u8 msdu_payload[0];
 } __packed;
 
+struct hal_rx_desc_qcn9074 {
+       __le32 msdu_end_tag;
+       struct rx_msdu_end_qcn9074 msdu_end;
+       __le32 rx_attn_tag;
+       struct rx_attention attention;
+       __le32 msdu_start_tag;
+       struct rx_msdu_start_qcn9074 msdu_start;
+       u8 rx_padding0[HAL_RX_DESC_PADDING0_BYTES];
+       __le32 mpdu_start_tag;
+       struct rx_mpdu_start_qcn9074 mpdu_start;
+       __le32 mpdu_end_tag;
+       struct rx_mpdu_end mpdu_end;
+       u8 rx_padding1[HAL_RX_DESC_PADDING1_BYTES];
+       __le32 hdr_status_tag;
+       __le32 phy_ppdu_id;
+       u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN];
+       u8 msdu_payload[0];
+} __packed;
+
+struct hal_rx_desc {
+       union {
+               struct hal_rx_desc_ipq8074 ipq8074;
+               struct hal_rx_desc_qcn9074 qcn9074;
+       } u;
+} __packed;
+
 #define HAL_RX_RU_ALLOC_TYPE_MAX 6
 #define RU_26  1
 #define RU_52  2
index cccfd3b..5ca2d80 100644 (file)
@@ -5417,31 +5417,6 @@ int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb,
        return 0;
 }
 
-static int
-ath11k_pull_pdev_temp_ev(struct ath11k_base *ab, u8 *evt_buf,
-                        u32 len, const struct wmi_pdev_temperature_event *ev)
-{
-       const void **tb;
-       int ret;
-
-       tb = ath11k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);
-       if (IS_ERR(tb)) {
-               ret = PTR_ERR(tb);
-               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
-               return ret;
-       }
-
-       ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT];
-       if (!ev) {
-               ath11k_warn(ab, "failed to fetch pdev temp ev");
-               kfree(tb);
-               return -EPROTO;
-       }
-
-       kfree(tb);
-       return 0;
-}
-
 size_t ath11k_wmi_fw_stats_num_vdevs(struct list_head *head)
 {
        struct ath11k_fw_stats_vdev *i;
@@ -6196,10 +6171,8 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb)
                }
        }
 
-       /* TODO: Pending handle beacon implementation
-        *if (ieee80211_is_beacon(hdr->frame_control))
-        *      ath11k_mac_handle_beacon(ar, skb);
-        */
+       if (ieee80211_is_beacon(hdr->frame_control))
+               ath11k_mac_handle_beacon(ar, skb);
 
        ath11k_dbg(ab, ATH11K_DBG_MGMT,
                   "event mgmt rx skb %pK len %d ftype %02x stype %02x\n",
@@ -6418,10 +6391,7 @@ static void ath11k_roam_event(struct ath11k_base *ab, struct sk_buff *skb)
 
        switch (roam_ev.reason) {
        case WMI_ROAM_REASON_BEACON_MISS:
-               /* TODO: Pending beacon miss and connection_loss_work
-                * implementation
-                * ath11k_mac_handle_beacon_miss(ar, vdev_id);
-                */
+               ath11k_mac_handle_beacon_miss(ar, roam_ev.vdev_id);
                break;
        case WMI_ROAM_REASON_BETTER_AP:
        case WMI_ROAM_REASON_LOW_RSSI:
@@ -6849,23 +6819,37 @@ ath11k_wmi_pdev_temperature_event(struct ath11k_base *ab,
                                  struct sk_buff *skb)
 {
        struct ath11k *ar;
-       struct wmi_pdev_temperature_event ev = {0};
+       const void **tb;
+       const struct wmi_pdev_temperature_event *ev;
+       int ret;
 
-       if (ath11k_pull_pdev_temp_ev(ab, skb->data, skb->len, &ev) != 0) {
-               ath11k_warn(ab, "failed to extract pdev temperature event");
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return;
+       }
+
+       ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch pdev temp ev");
+               kfree(tb);
                return;
        }
 
        ath11k_dbg(ab, ATH11K_DBG_WMI,
-                  "pdev temperature ev temp %d pdev_id %d\n", ev.temp, ev.pdev_id);
+                  "pdev temperature ev temp %d pdev_id %d\n", ev->temp, ev->pdev_id);
 
-       ar = ath11k_mac_get_ar_by_pdev_id(ab, ev.pdev_id);
+       ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id);
        if (!ar) {
-               ath11k_warn(ab, "invalid pdev id in pdev temperature ev %d", ev.pdev_id);
+               ath11k_warn(ab, "invalid pdev id in pdev temperature ev %d", ev->pdev_id);
+               kfree(tb);
                return;
        }
 
-       ath11k_thermal_event_temperature(ar, ev.temp);
+       ath11k_thermal_event_temperature(ar, ev->temp);
+
+       kfree(tb);
 }
 
 static void ath11k_fils_discovery_event(struct ath11k_base *ab,
index 01f9c26..e9a36dd 100644 (file)
@@ -617,7 +617,6 @@ static int ath9k_of_init(struct ath_softc *sc)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        enum ath_bus_type bus_type = common->bus_ops->ath_bus_type;
-       const char *mac;
        char eeprom_name[100];
        int ret;
 
@@ -640,9 +639,7 @@ static int ath9k_of_init(struct ath_softc *sc)
                ah->ah_flags |= AH_NO_EEP_SWAP;
        }
 
-       mac = of_get_mac_address(np);
-       if (!IS_ERR(mac))
-               ether_addr_copy(common->macaddr, mac);
+       of_get_mac_address(np, common->macaddr);
 
        return 0;
 }
index 4ca8212..6ff2674 100644 (file)
@@ -751,9 +751,7 @@ il3945_hdl_alive(struct il_priv *il, struct il_rx_buf *rxb)
 static void
 il3945_hdl_add_sta(struct il_priv *il, struct il_rx_buf *rxb)
 {
-#ifdef CONFIG_IWLEGACY_DEBUG
        struct il_rx_pkt *pkt = rxb_addr(rxb);
-#endif
 
        D_RX("Received C_ADD_STA: 0x%02X\n", pkt->u.status);
 }
index 0651a6a..219fed9 100644 (file)
@@ -1430,10 +1430,8 @@ static void
 il_hdl_scan_complete(struct il_priv *il, struct il_rx_buf *rxb)
 {
 
-#ifdef CONFIG_IWLEGACY_DEBUG
        struct il_rx_pkt *pkt = rxb_addr(rxb);
        struct il_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
-#endif
 
        D_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
               scan_notif->scanned_channels, scan_notif->tsf_low,
index ea1b1bb..40877ef 100644 (file)
@@ -2937,7 +2937,7 @@ do {                                                                      \
 } while (0)
 
 #else
-#define IL_DBG(level, fmt, args...)
+#define IL_DBG(level, fmt, args...) no_printk(fmt, ##args)
 static inline void
 il_print_hex_dump(struct il_priv *il, int level, const void *p, u32 len)
 {
index 665b54c..6d89573 100644 (file)
@@ -91,16 +91,9 @@ void
 mt76_eeprom_override(struct mt76_phy *phy)
 {
        struct mt76_dev *dev = phy->dev;
-
-#ifdef CONFIG_OF
        struct device_node *np = dev->dev->of_node;
-       const u8 *mac = NULL;
 
-       if (np)
-               mac = of_get_mac_address(np);
-       if (!IS_ERR_OR_NULL(mac))
-               ether_addr_copy(phy->macaddr, mac);
-#endif
+       of_get_mac_address(np, phy->macaddr);
 
        if (!is_valid_ether_addr(phy->macaddr)) {
                eth_random_addr(phy->macaddr);
index c868582..aa3b649 100644 (file)
@@ -99,7 +99,7 @@ mt7601u_has_tssi(struct mt7601u_dev *dev, u8 *eeprom)
 {
        u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
 
-       return ~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN);
+       return (u16)~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN);
 }
 
 static void
index cada488..5d9e952 100644 (file)
@@ -610,6 +610,7 @@ int mt7601u_register_device(struct mt7601u_dev *dev)
 
        wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
        wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
 
        wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
 
index 1b205e7..9928e91 100644 (file)
 
 static irqreturn_t isr_uh_routine(int irq, void *user_data)
 {
-       struct net_device *dev = user_data;
-       struct wilc_vif *vif = netdev_priv(dev);
-       struct wilc *wilc = vif->wilc;
+       struct wilc *wilc = user_data;
 
        if (wilc->close) {
-               netdev_err(dev, "Can't handle UH interrupt\n");
+               pr_err("Can't handle UH interrupt");
                return IRQ_HANDLED;
        }
        return IRQ_WAKE_THREAD;
@@ -37,12 +35,10 @@ static irqreturn_t isr_uh_routine(int irq, void *user_data)
 
 static irqreturn_t isr_bh_routine(int irq, void *userdata)
 {
-       struct net_device *dev = userdata;
-       struct wilc_vif *vif = netdev_priv(userdata);
-       struct wilc *wilc = vif->wilc;
+       struct wilc *wilc = userdata;
 
        if (wilc->close) {
-               netdev_err(dev, "Can't handle BH interrupt\n");
+               pr_err("Can't handle BH interrupt\n");
                return IRQ_HANDLED;
        }
 
@@ -60,7 +56,7 @@ static int init_irq(struct net_device *dev)
        ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine,
                                   isr_bh_routine,
                                   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                  "WILC_IRQ", dev);
+                                  "WILC_IRQ", wl);
        if (ret) {
                netdev_err(dev, "Failed to request IRQ [%d]\n", ret);
                return ret;
index 351ff90..e14b9fc 100644 (file)
@@ -947,7 +947,7 @@ static int wilc_sdio_sync_ext(struct wilc *wilc, int nint)
                        for (i = 0; (i < 3) && (nint > 0); i++, nint--)
                                reg |= BIT(i);
 
-                       ret = wilc_sdio_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
+                       ret = wilc_sdio_write_reg(wilc, WILC_INTR2_ENABLE, reg);
                        if (ret) {
                                dev_err(&func->dev,
                                        "Failed write reg (%08x)...\n",
index 31d5138..d4a90c4 100644 (file)
@@ -552,12 +552,60 @@ static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
 void chip_allow_sleep(struct wilc *wilc)
 {
        u32 reg = 0;
+       const struct wilc_hif_func *hif_func = wilc->hif_func;
+       u32 wakeup_reg, wakeup_bit;
+       u32 to_host_from_fw_reg, to_host_from_fw_bit;
+       u32 from_host_to_fw_reg, from_host_to_fw_bit;
+       u32 trials = 100;
+       int ret;
+
+       if (wilc->io_type == WILC_HIF_SDIO) {
+               wakeup_reg = WILC_SDIO_WAKEUP_REG;
+               wakeup_bit = WILC_SDIO_WAKEUP_BIT;
+               from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG;
+               from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT;
+               to_host_from_fw_reg = WILC_SDIO_FW_TO_HOST_REG;
+               to_host_from_fw_bit = WILC_SDIO_FW_TO_HOST_BIT;
+       } else {
+               wakeup_reg = WILC_SPI_WAKEUP_REG;
+               wakeup_bit = WILC_SPI_WAKEUP_BIT;
+               from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG;
+               from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT;
+               to_host_from_fw_reg = WILC_SPI_FW_TO_HOST_REG;
+               to_host_from_fw_bit = WILC_SPI_FW_TO_HOST_BIT;
+       }
+
+       while (trials--) {
+               ret = hif_func->hif_read_reg(wilc, to_host_from_fw_reg, &reg);
+               if (ret)
+                       return;
+               if ((reg & to_host_from_fw_bit) == 0)
+                       break;
+       }
+       if (!trials)
+               pr_warn("FW not responding\n");
 
-       wilc->hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, &reg);
+       /* Clear bit 1 */
+       ret = hif_func->hif_read_reg(wilc, wakeup_reg, &reg);
+       if (ret)
+               return;
+       if (reg & wakeup_bit) {
+               reg &= ~wakeup_bit;
+               ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg);
+               if (ret)
+                       return;
+       }
 
-       wilc->hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG,
-                                     reg & ~WILC_SDIO_WAKEUP_BIT);
-       wilc->hif_func->hif_write_reg(wilc, WILC_SDIO_HOST_TO_FW_REG, 0);
+       ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, &reg);
+       if (ret)
+               return;
+       if (reg & from_host_to_fw_bit) {
+               reg &= ~from_host_to_fw_bit;
+               ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, reg);
+               if (ret)
+                       return;
+
+       }
 }
 EXPORT_SYMBOL_GPL(chip_allow_sleep);
 
index d55eb6b..6479acc 100644 (file)
 #define WILC_SPI_WAKEUP_REG            0x1
 #define WILC_SPI_WAKEUP_BIT            BIT(1)
 
+#define WILC_SPI_HOST_TO_FW_REG                0x0b
+#define WILC_SPI_HOST_TO_FW_BIT                BIT(0)
+
+#define WILC_SPI_FW_TO_HOST_REG                0x10
+#define WILC_SPI_FW_TO_HOST_BIT                BIT(0)
+
 #define WILC_SPI_PROTOCOL_OFFSET       (WILC_SPI_PROTOCOL_CONFIG - \
                                         WILC_SPI_REG_BASE)
 
index 61a4f1a..e95c101 100644 (file)
@@ -989,11 +989,7 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry,
 
 void rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
 {
-       const char *mac_addr;
-
-       mac_addr = of_get_mac_address(rt2x00dev->dev->of_node);
-       if (!IS_ERR(mac_addr))
-               ether_addr_copy(eeprom_mac_addr, mac_addr);
+       of_get_mac_address(rt2x00dev->dev->of_node, eeprom_mac_addr);
 
        if (!is_valid_ether_addr(eeprom_mac_addr)) {
                eth_random_addr(eeprom_mac_addr);
index ea2be1e..cedbf38 100644 (file)
@@ -787,7 +787,6 @@ static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
 {
        struct rtw_chip_info *chip = rtwdev->chip;
        struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm;
-       struct rtw_efuse *efuse = &rtwdev->efuse;
        u8 link = 0;
        u8 center_chan = 0;
        u8 bw;
@@ -798,7 +797,7 @@ static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
        if (type != COEX_MEDIA_DISCONNECT)
                center_chan = rtwdev->hal.current_channel;
 
-       if (center_chan == 0 || (efuse->share_ant && center_chan <= 14)) {
+       if (center_chan == 0) {
                link = 0;
                center_chan = 0;
                bw = 0;
@@ -2325,8 +2324,11 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
        if (efuse->share_ant) { /* Shared-Ant */
                if (coex_stat->bt_a2dp_exist) {
                        slot_type = TDMA_4SLOT;
-                       table_case = 9;
                        tdma_case = 11;
+                       if (coex_stat->wl_gl_busy)
+                               table_case = 26;
+                       else
+                               table_case = 9;
                } else {
                        table_case = 9;
                        tdma_case = 7;
@@ -2646,6 +2648,11 @@ void rtw_coex_power_on_setting(struct rtw_dev *rtwdev)
        rtw_coex_set_gnt_debug(rtwdev);
 }
 
+void rtw_coex_power_off_setting(struct rtw_dev *rtwdev)
+{
+       rtw_write16(rtwdev, REG_WIFI_BT_INFO, BIT_BT_INT_EN);
+}
+
 void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
 {
        __rtw_coex_init_hw_config(rtwdev, wifi_only);
index 8ab9852..5701870 100644 (file)
@@ -393,6 +393,7 @@ void rtw_coex_bt_multi_link_remain_work(struct work_struct *work);
 void rtw_coex_wl_ccklock_work(struct work_struct *work);
 
 void rtw_coex_power_on_setting(struct rtw_dev *rtwdev);
+void rtw_coex_power_off_setting(struct rtw_dev *rtwdev);
 void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only);
 void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type);
 void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type);
index 948cb79..5c44fa8 100644 (file)
@@ -10,6 +10,7 @@
 #include "fw.h"
 #include "debug.h"
 #include "phy.h"
+#include "reg.h"
 
 #ifdef CONFIG_RTW88_DEBUGFS
 
@@ -270,7 +271,7 @@ static ssize_t rtw_debugfs_set_rsvd_page(struct file *filp,
 
        if (num != 2) {
                rtw_warn(rtwdev, "invalid arguments\n");
-               return num;
+               return -EINVAL;
        }
 
        debugfs_priv->rsvd_page.page_offset = offset;
@@ -818,6 +819,40 @@ static int rtw_debugfs_get_coex_enable(struct seq_file *m, void *v)
        return 0;
 }
 
+static ssize_t rtw_debugfs_set_fw_crash(struct file *filp,
+                                       const char __user *buffer,
+                                       size_t count, loff_t *loff)
+{
+       struct seq_file *seqpriv = (struct seq_file *)filp->private_data;
+       struct rtw_debugfs_priv *debugfs_priv = seqpriv->private;
+       struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
+       char tmp[32 + 1];
+       bool input;
+       int ret;
+
+       rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1);
+
+       ret = kstrtobool(tmp, &input);
+       if (ret)
+               return -EINVAL;
+
+       if (!input)
+               return -EINVAL;
+
+       rtw_write8(rtwdev, REG_HRCV_MSG, 1);
+
+       return count;
+}
+
+static int rtw_debugfs_get_fw_crash(struct seq_file *m, void *v)
+{
+       struct rtw_debugfs_priv *debugfs_priv = m->private;
+       struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
+
+       seq_printf(m, "%d\n", test_bit(RTW_FLAG_RESTARTING, rtwdev->flags));
+       return 0;
+}
+
 #define rtw_debug_impl_mac(page, addr)                         \
 static struct rtw_debugfs_priv rtw_debug_priv_mac_ ##page = {  \
        .cb_read = rtw_debug_get_mac_page,                      \
@@ -921,6 +956,11 @@ static struct rtw_debugfs_priv rtw_debug_priv_coex_info = {
        .cb_read = rtw_debugfs_get_coex_info,
 };
 
+static struct rtw_debugfs_priv rtw_debug_priv_fw_crash = {
+       .cb_write = rtw_debugfs_set_fw_crash,
+       .cb_read = rtw_debugfs_get_fw_crash,
+};
+
 #define rtw_debugfs_add_core(name, mode, fopname, parent)              \
        do {                                                            \
                rtw_debug_priv_ ##name.rtwdev = rtwdev;                 \
@@ -994,6 +1034,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev)
        }
        rtw_debugfs_add_r(rf_dump);
        rtw_debugfs_add_r(tx_pwr_tbl);
+       rtw_debugfs_add_rw(fw_crash);
 }
 
 #endif /* CONFIG_RTW88_DEBUGFS */
index 2cba327..4c6fc6f 100644 (file)
@@ -11,6 +11,7 @@ struct rtw_hci_ops {
                        struct rtw_tx_pkt_info *pkt_info,
                        struct sk_buff *skb);
        void (*tx_kick_off)(struct rtw_dev *rtwdev);
+       void (*flush_queues)(struct rtw_dev *rtwdev, u32 queues, bool drop);
        int (*setup)(struct rtw_dev *rtwdev);
        int (*start)(struct rtw_dev *rtwdev);
        void (*stop)(struct rtw_dev *rtwdev);
@@ -258,4 +259,19 @@ static inline enum rtw_hci_type rtw_hci_type(struct rtw_dev *rtwdev)
        return rtwdev->hci.type;
 }
 
+static inline void rtw_hci_flush_queues(struct rtw_dev *rtwdev, u32 queues,
+                                       bool drop)
+{
+       if (rtwdev->hci.ops->flush_queues)
+               rtwdev->hci.ops->flush_queues(rtwdev, queues, drop);
+}
+
+static inline void rtw_hci_flush_all_queues(struct rtw_dev *rtwdev, bool drop)
+{
+       if (rtwdev->hci.ops->flush_queues)
+               rtwdev->hci.ops->flush_queues(rtwdev,
+                                             BIT(rtwdev->hw->queues) - 1,
+                                             drop);
+}
+
 #endif
index 59028b1..d1678ae 100644 (file)
@@ -530,6 +530,25 @@ static int iddma_download_firmware(struct rtw_dev *rtwdev, u32 src, u32 dst,
        return 0;
 }
 
+int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size)
+{
+       u32 ch0_ctrl = BIT_DDMACH0_OWN | BIT_DDMACH0_DDMA_MODE;
+
+       if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) {
+               rtw_dbg(rtwdev, RTW_DBG_FW, "busy to start ddma\n");
+               return -EBUSY;
+       }
+
+       ch0_ctrl |= size & BIT_MASK_DDMACH0_DLEN;
+
+       if (iddma_enable(rtwdev, ocp_src, OCPBASE_RXBUF_FW_88XX, ch0_ctrl)) {
+               rtw_dbg(rtwdev, RTW_DBG_FW, "busy to complete ddma\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
 static bool
 check_fw_checksum(struct rtw_dev *rtwdev, u32 addr)
 {
index ce64cdf..3172aa5 100644 (file)
 #define ILLEGAL_KEY_GROUP      0xFAAAAA00
 
 /* HW memory address */
+#define OCPBASE_RXBUF_FW_88XX          0x18680000
 #define OCPBASE_TXBUF_88XX             0x18780000
+#define OCPBASE_ROM_88XX               0x00000000
+#define OCPBASE_IMEM_88XX              0x00030000
 #define OCPBASE_DMEM_88XX              0x00200000
 #define OCPBASE_EMEM_88XX              0x00100000
 
@@ -33,6 +36,7 @@ void rtw_mac_power_off(struct rtw_dev *rtwdev);
 int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw);
 int rtw_mac_init(struct rtw_dev *rtwdev);
 void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop);
+int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size);
 
 static inline void rtw_mac_flush_all_queues(struct rtw_dev *rtwdev, bool drop)
 {
index 2351dfb..333df6b 100644 (file)
@@ -520,6 +520,7 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                                  hw_key_type, hw_key_idx);
                break;
        case DISABLE_KEY:
+               rtw_hci_flush_all_queues(rtwdev, false);
                rtw_mac_flush_all_queues(rtwdev, false);
                rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx);
                break;
@@ -670,6 +671,7 @@ static void rtw_ops_flush(struct ieee80211_hw *hw,
        mutex_lock(&rtwdev->mutex);
        rtw_leave_lps_deep(rtwdev);
 
+       rtw_hci_flush_queues(rtwdev, queues, drop);
        rtw_mac_flush_queues(rtwdev, queues, drop);
        mutex_unlock(&rtwdev->mutex);
 }
index e6989c0..f3a3a86 100644 (file)
@@ -345,15 +345,9 @@ static bool rtw_fw_dump_crash_log(struct rtw_dev *rtwdev)
                        "fw crash dump's seq is wrong: %d\n", seq);
                goto free_buf;
        }
-       if (seq == 0 &&
-           (GET_FW_DUMP_TLV_TYPE(buf) != FW_CD_TYPE ||
-            GET_FW_DUMP_TLV_LEN(buf) != FW_CD_LEN ||
-            GET_FW_DUMP_TLV_VAL(buf) != FW_CD_VAL)) {
-               rtw_dbg(rtwdev, RTW_DBG_FW, "fw crash dump's tlv is wrong\n");
-               goto free_buf;
-       }
 
-       print_hex_dump_bytes("rtw88 fw dump: ", DUMP_PREFIX_OFFSET, buf, size);
+       print_hex_dump(KERN_ERR, "rtw88 fw dump: ", DUMP_PREFIX_OFFSET, 16, 1,
+                      buf, size, true);
 
        if (GET_FW_DUMP_MORE(buf) == 1) {
                rtwdev->fw.prev_dump_seq = seq;
@@ -368,6 +362,78 @@ exit:
        return ret;
 }
 
+int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size,
+               const char *prefix_str)
+{
+       u32 rxff = rtwdev->chip->fw_rxff_size;
+       u32 dump_size, done_size = 0;
+       u8 *buf;
+       int ret;
+
+       buf = vzalloc(size);
+       if (!buf)
+               return -ENOMEM;
+
+       while (size) {
+               dump_size = size > rxff ? rxff : size;
+
+               ret = rtw_ddma_to_fw_fifo(rtwdev, ocp_src + done_size,
+                                         dump_size);
+               if (ret) {
+                       rtw_err(rtwdev,
+                               "ddma fw 0x%x [+0x%x] to fw fifo fail\n",
+                               ocp_src, done_size);
+                       goto exit;
+               }
+
+               ret = rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0,
+                                      dump_size, (u32 *)(buf + done_size));
+               if (ret) {
+                       rtw_err(rtwdev,
+                               "dump fw 0x%x [+0x%x] from fw fifo fail\n",
+                               ocp_src, done_size);
+                       goto exit;
+               }
+
+               size -= dump_size;
+               done_size += dump_size;
+       }
+
+       print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 1,
+                      buf, done_size, true);
+
+exit:
+       vfree(buf);
+       return ret;
+}
+EXPORT_SYMBOL(rtw_dump_fw);
+
+int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size,
+                const char *prefix_str)
+{
+       u8 *buf;
+       u32 i;
+
+       if (addr & 0x3) {
+               WARN(1, "should be 4-byte aligned, addr = 0x%08x\n", addr);
+               return -EINVAL;
+       }
+
+       buf = vzalloc(size);
+       if (!buf)
+               return -ENOMEM;
+
+       for (i = 0; i < size; i += 4)
+               *(u32 *)(buf + i) = rtw_read32(rtwdev, addr + i);
+
+       print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 4, buf,
+                      size, true);
+
+       vfree(buf);
+       return 0;
+}
+EXPORT_SYMBOL(rtw_dump_reg);
+
 void rtw_vif_assoc_changed(struct rtw_vif *rtwvif,
                           struct ieee80211_bss_conf *conf)
 {
@@ -419,10 +485,8 @@ void rtw_fw_recovery(struct rtw_dev *rtwdev)
                ieee80211_queue_work(rtwdev->hw, &rtwdev->fw_recovery_work);
 }
 
-static void rtw_fw_recovery_work(struct work_struct *work)
+static void __fw_recovery_work(struct rtw_dev *rtwdev)
 {
-       struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
-                                             fw_recovery_work);
 
        /* rtw_fw_dump_crash_log() returns false indicates that there are
         * still more log to dump. Driver set 0x1cf[7:0] = 0x1 to tell firmware
@@ -435,18 +499,26 @@ static void rtw_fw_recovery_work(struct work_struct *work)
        }
        rtwdev->fw.prev_dump_seq = 0;
 
-       WARN(1, "firmware crash, start reset and recover\n");
+       set_bit(RTW_FLAG_RESTARTING, rtwdev->flags);
+       rtw_chip_dump_fw_crash(rtwdev);
 
-       mutex_lock(&rtwdev->mutex);
+       WARN(1, "firmware crash, start reset and recover\n");
 
-       set_bit(RTW_FLAG_RESTARTING, rtwdev->flags);
        rcu_read_lock();
        rtw_iterate_keys_rcu(rtwdev, NULL, rtw_reset_key_iter, rtwdev);
        rcu_read_unlock();
        rtw_iterate_stas_atomic(rtwdev, rtw_reset_sta_iter, rtwdev);
        rtw_iterate_vifs_atomic(rtwdev, rtw_reset_vif_iter, rtwdev);
        rtw_enter_ips(rtwdev);
+}
 
+static void rtw_fw_recovery_work(struct work_struct *work)
+{
+       struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
+                                             fw_recovery_work);
+
+       mutex_lock(&rtwdev->mutex);
+       __fw_recovery_work(rtwdev);
        mutex_unlock(&rtwdev->mutex);
 
        ieee80211_restart_hw(rtwdev->hw);
@@ -1138,6 +1210,7 @@ int rtw_core_start(struct rtw_dev *rtwdev)
 static void rtw_power_off(struct rtw_dev *rtwdev)
 {
        rtw_hci_stop(rtwdev);
+       rtw_coex_power_off_setting(rtwdev);
        rtw_mac_power_off(rtwdev);
 }
 
@@ -1393,7 +1466,6 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev)
        struct rtw_chip_info *chip = rtwdev->chip;
        struct rtw_hal *hal = &rtwdev->hal;
        struct rtw_efuse *efuse = &rtwdev->efuse;
-       int ret = 0;
 
        switch (rtw_hci_type(rtwdev)) {
        case RTW_HCI_TYPE_PCIE:
@@ -1431,7 +1503,7 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev)
 
        hal->bfee_sts_cap = 3;
 
-       return ret;
+       return 0;
 }
 
 static int rtw_chip_efuse_enable(struct rtw_dev *rtwdev)
index 35afea9..98b18da 100644 (file)
@@ -805,6 +805,7 @@ struct rtw_regulatory {
 
 struct rtw_chip_ops {
        int (*mac_init)(struct rtw_dev *rtwdev);
+       void (*dump_fw_crash)(struct rtw_dev *rtwdev);
        void (*shutdown)(struct rtw_dev *rtwdev);
        int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map);
        void (*phy_set_param)(struct rtw_dev *rtwdev);
@@ -1166,6 +1167,7 @@ struct rtw_chip_info {
        bool en_dis_dpd;
        u16 dpd_ratemask;
        u8 iqk_threshold;
+       u8 lck_threshold;
        const struct rtw_pwr_track_tbl *pwr_track_tbl;
 
        u8 bfer_su_max_num;
@@ -1534,6 +1536,7 @@ struct rtw_dm_info {
        u32 rrsr_mask_min;
        u8 thermal_avg[RTW_RF_PATH_MAX];
        u8 thermal_meter_k;
+       u8 thermal_meter_lck;
        s8 delta_power_index[RTW_RF_PATH_MAX];
        s8 delta_power_index_last[RTW_RF_PATH_MAX];
        u8 default_ofdm_index;
@@ -1876,6 +1879,12 @@ static inline void rtw_release_macid(struct rtw_dev *rtwdev, u8 mac_id)
        clear_bit(mac_id, rtwdev->mac_id_map);
 }
 
+static inline void rtw_chip_dump_fw_crash(struct rtw_dev *rtwdev)
+{
+       if (rtwdev->chip->ops->dump_fw_crash)
+               rtwdev->chip->ops->dump_fw_crash(rtwdev);
+}
+
 void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
                            struct rtw_channel_params *ch_param);
 bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target);
@@ -1905,5 +1914,9 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
 void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
                    bool fw_exist);
 void rtw_fw_recovery(struct rtw_dev *rtwdev);
+int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size,
+               const char *prefix_str);
+int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size,
+                const char *prefix_str);
 
 #endif
index 786a486..b8115b3 100644 (file)
@@ -671,6 +671,8 @@ static u8 ac_to_hwq[] = {
        [IEEE80211_AC_BK] = RTW_TX_QUEUE_BK,
 };
 
+static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS);
+
 static u8 rtw_hw_queue_mapping(struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -727,6 +729,72 @@ static void rtw_pci_dma_check(struct rtw_dev *rtwdev,
        rtwpci->rx_tag = (rtwpci->rx_tag + 1) % RX_TAG_MAX;
 }
 
+static u32 __pci_get_hw_tx_ring_rp(struct rtw_dev *rtwdev, u8 pci_q)
+{
+       u32 bd_idx_addr = rtw_pci_tx_queue_idx_addr[pci_q];
+       u32 bd_idx = rtw_read16(rtwdev, bd_idx_addr + 2);
+
+       return FIELD_GET(TRX_BD_IDX_MASK, bd_idx);
+}
+
+static void __pci_flush_queue(struct rtw_dev *rtwdev, u8 pci_q, bool drop)
+{
+       struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+       struct rtw_pci_tx_ring *ring = &rtwpci->tx_rings[pci_q];
+       u32 cur_rp;
+       u8 i;
+
+       /* Because the time taked by the I/O in __pci_get_hw_tx_ring_rp is a
+        * bit dynamic, it's hard to define a reasonable fixed total timeout to
+        * use read_poll_timeout* helper. Instead, we can ensure a reasonable
+        * polling times, so we just use for loop with udelay here.
+        */
+       for (i = 0; i < 30; i++) {
+               cur_rp = __pci_get_hw_tx_ring_rp(rtwdev, pci_q);
+               if (cur_rp == ring->r.wp)
+                       return;
+
+               udelay(1);
+       }
+
+       if (!drop)
+               rtw_warn(rtwdev, "timed out to flush pci tx ring[%d]\n", pci_q);
+}
+
+static void __rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 pci_queues,
+                                  bool drop)
+{
+       u8 q;
+
+       for (q = 0; q < RTK_MAX_TX_QUEUE_NUM; q++) {
+               /* It may be not necessary to flush BCN and H2C tx queues. */
+               if (q == RTW_TX_QUEUE_BCN || q == RTW_TX_QUEUE_H2C)
+                       continue;
+
+               if (pci_queues & BIT(q))
+                       __pci_flush_queue(rtwdev, q, drop);
+       }
+}
+
+static void rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop)
+{
+       u32 pci_queues = 0;
+       u8 i;
+
+       /* If all of the hardware queues are requested to flush,
+        * flush all of the pci queues.
+        */
+       if (queues == BIT(rtwdev->hw->queues) - 1) {
+               pci_queues = BIT(RTK_MAX_TX_QUEUE_NUM) - 1;
+       } else {
+               for (i = 0; i < rtwdev->hw->queues; i++)
+                       if (queues & BIT(i))
+                               pci_queues |= BIT(ac_to_hwq[i]);
+       }
+
+       __rtw_pci_flush_queues(rtwdev, pci_queues, drop);
+}
+
 static void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev, u8 queue)
 {
        struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
@@ -1490,6 +1558,7 @@ static void rtw_pci_destroy(struct rtw_dev *rtwdev, struct pci_dev *pdev)
 static struct rtw_hci_ops rtw_pci_ops = {
        .tx_write = rtw_pci_tx_write,
        .tx_kick_off = rtw_pci_tx_kick_off,
+       .flush_queues = rtw_pci_flush_queues,
        .setup = rtw_pci_setup,
        .start = rtw_pci_start,
        .stop = rtw_pci_stop,
index e114dde..b3c0a38 100644 (file)
@@ -316,7 +316,8 @@ rtw_phy_dig_check_damping(struct rtw_dm_info *dm_info)
        return damping;
 }
 
-static void rtw_phy_dig_get_boundary(struct rtw_dm_info *dm_info,
+static void rtw_phy_dig_get_boundary(struct rtw_dev *rtwdev,
+                                    struct rtw_dm_info *dm_info,
                                     u8 *upper, u8 *lower, bool linked)
 {
        u8 dig_max, dig_min, dig_mid;
@@ -325,8 +326,7 @@ static void rtw_phy_dig_get_boundary(struct rtw_dm_info *dm_info,
        if (linked) {
                dig_max = DIG_PERF_MAX;
                dig_mid = DIG_PERF_MID;
-               /* 22B=0x1c, 22C=0x20 */
-               dig_min = 0x1c;
+               dig_min = rtwdev->chip->dig_min;
                min_rssi = max_t(u8, dm_info->min_rssi, dig_min);
        } else {
                dig_max = DIG_CVRG_MAX;
@@ -437,7 +437,8 @@ static void rtw_phy_dig(struct rtw_dev *rtwdev)
         * the peers connected with us, meanwhile make sure the igi value does
         * not beyond the hardware limitation
         */
-       rtw_phy_dig_get_boundary(dm_info, &upper_bound, &lower_bound, linked);
+       rtw_phy_dig_get_boundary(rtwdev, dm_info, &upper_bound, &lower_bound,
+                                linked);
        cur_igi = clamp_t(u8, cur_igi, lower_bound, upper_bound);
 
        /* record current igi value and false alarm statistics for further
@@ -2219,6 +2220,20 @@ s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev,
 }
 EXPORT_SYMBOL(rtw_phy_pwrtrack_get_pwridx);
 
+bool rtw_phy_pwrtrack_need_lck(struct rtw_dev *rtwdev)
+{
+       struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+       u8 delta_lck;
+
+       delta_lck = abs(dm_info->thermal_avg[0] - dm_info->thermal_meter_lck);
+       if (delta_lck >= rtwdev->chip->lck_threshold) {
+               dm_info->thermal_meter_lck = dm_info->thermal_avg[0];
+               return true;
+       }
+       return false;
+}
+EXPORT_SYMBOL(rtw_phy_pwrtrack_need_lck);
+
 bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev)
 {
        struct rtw_dm_info *dm_info = &rtwdev->dm_info;
index a4fcfb8..a0742a6 100644 (file)
@@ -55,6 +55,7 @@ u8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path);
 s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev,
                               struct rtw_swing_table *swing_table,
                               u8 tbl_path, u8 therm_path, u8 delta);
+bool rtw_phy_pwrtrack_need_lck(struct rtw_dev *rtwdev);
 bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev);
 void rtw_phy_config_swing_table(struct rtw_dev *rtwdev,
                                struct rtw_swing_table *swing_table);
index ea518aa..a85fe29 100644 (file)
 #define BIT_DDMACH0_OWN                BIT(31)
 #define BIT_DDMACH0_CHKSUM_EN  BIT(29)
 #define BIT_DDMACH0_CHKSUM_STS BIT(27)
+#define BIT_DDMACH0_DDMA_MODE  BIT(26)
 #define BIT_DDMACH0_RESET_CHKSUM_STS BIT(25)
 #define BIT_DDMACH0_CHKSUM_CONT        BIT(24)
 #define BIT_MASK_DDMACH0_DLEN  0x3ffff
 #define RF_TXATANK     0x64
 #define RF_TRXIQ       0x66
 #define RF_RXIQGEN     0x8d
+#define RF_SYN_PFD     0xb0
 #define RF_XTALX2      0xb8
+#define RF_SYN_CTRL    0xbb
 #define RF_MALSEL      0xbe
+#define RF_SYN_AAC     0xc9
+#define RF_AAC_CTRL    0xca
+#define RF_FAST_LCK    0xcc
 #define RF_RCKD                0xde
 #define RF_TXADBG      0xde
 #define RF_LUTDBG      0xdf
index dd560c2..07ff0d4 100644 (file)
@@ -1126,6 +1126,7 @@ static void rtw8822c_pwrtrack_init(struct rtw_dev *rtwdev)
 
        dm_info->pwr_trk_triggered = false;
        dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k;
+       dm_info->thermal_meter_lck = rtwdev->efuse.thermal_meter_k;
 }
 
 static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev)
@@ -1396,6 +1397,15 @@ static int rtw8822c_mac_init(struct rtw_dev *rtwdev)
        return 0;
 }
 
+static void rtw8822c_dump_fw_crash(struct rtw_dev *rtwdev)
+{
+       rtw_dump_reg(rtwdev, 0x0, 0x2000, "rtw8822c reg_");
+       rtw_dump_fw(rtwdev, OCPBASE_DMEM_88XX, 0x10000, "rtw8822c DMEM_");
+       rtw_dump_fw(rtwdev, OCPBASE_IMEM_88XX, 0x10000, "rtw8822c IMEM_");
+       rtw_dump_fw(rtwdev, OCPBASE_EMEM_88XX, 0x20000, "rtw8822c EMEM_");
+       rtw_dump_fw(rtwdev, OCPBASE_ROM_88XX, 0x10000, "rtw8822c ROM_");
+}
+
 static void rtw8822c_rstb_3wire(struct rtw_dev *rtwdev, bool enable)
 {
        if (enable) {
@@ -2108,6 +2118,26 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev)
        rtw_write32_set(rtwdev, REG_RX_BREAK, BIT_COM_RX_GCK_EN);
 }
 
+static void rtw8822c_do_lck(struct rtw_dev *rtwdev)
+{
+       u32 val;
+
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_SYN_CTRL, RFREG_MASK, 0x80010);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_SYN_PFD, RFREG_MASK, 0x1F0FA);
+       fsleep(1);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_AAC_CTRL, RFREG_MASK, 0x80000);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_SYN_AAC, RFREG_MASK, 0x80001);
+       read_poll_timeout(rtw_read_rf, val, val != 0x1, 1000, 100000,
+                         true, rtwdev, RF_PATH_A, RF_AAC_CTRL, 0x1000);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_SYN_PFD, RFREG_MASK, 0x1F0F8);
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_SYN_CTRL, RFREG_MASK, 0x80010);
+
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_FAST_LCK, RFREG_MASK, 0x0f000);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_FAST_LCK, RFREG_MASK, 0x4f000);
+       fsleep(1);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_FAST_LCK, RFREG_MASK, 0x0f000);
+}
+
 static void rtw8822c_do_iqk(struct rtw_dev *rtwdev)
 {
        struct rtw_iqk_para para = {0};
@@ -3538,11 +3568,12 @@ static void __rtw8822c_pwr_track(struct rtw_dev *rtwdev)
 
        rtw_phy_config_swing_table(rtwdev, &swing_table);
 
+       if (rtw_phy_pwrtrack_need_lck(rtwdev))
+               rtw8822c_do_lck(rtwdev);
+
        for (i = 0; i < rtwdev->hal.rf_path_num; i++)
                rtw8822c_pwr_track_path(rtwdev, &swing_table, i);
 
-       if (rtw_phy_pwrtrack_need_iqk(rtwdev))
-               rtw8822c_do_iqk(rtwdev);
 }
 
 static void rtw8822c_pwr_track(struct rtw_dev *rtwdev)
@@ -3971,6 +4002,7 @@ static struct rtw_chip_ops rtw8822c_ops = {
        .query_rx_desc          = rtw8822c_query_rx_desc,
        .set_channel            = rtw8822c_set_channel,
        .mac_init               = rtw8822c_mac_init,
+       .dump_fw_crash          = rtw8822c_dump_fw_crash,
        .read_rf                = rtw_phy_read_rf,
        .write_rf               = rtw_phy_write_rf_reg_mix,
        .set_tx_power_index     = rtw8822c_set_tx_power_index,
@@ -4351,6 +4383,7 @@ struct rtw_chip_info rtw8822c_hw_spec = {
        .dpd_ratemask = DIS_DPD_RATEALL,
        .pwr_track_tbl = &rtw8822c_rtw_pwr_track_tbl,
        .iqk_threshold = 8,
+       .lck_threshold = 8,
        .bfer_su_max_num = 2,
        .bfer_mu_max_num = 1,
        .rx_ldpc = true,
@@ -4360,7 +4393,7 @@ struct rtw_chip_info rtw8822c_hw_spec = {
        .wowlan_stub = &rtw_wowlan_stub_8822c,
        .max_sched_scan_ssids = 4,
 #endif
-       .coex_para_ver = 0x201029,
+       .coex_para_ver = 0x2103181c,
        .bt_desired_ver = 0x1c,
        .scbd_support = true,
        .new_scbd10_def = true,
index ad5715c..822f3da 100644 (file)
@@ -40863,7 +40863,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 8, 1, 0, 1, 144, 76, },
        { 9, 1, 0, 1, 144, 127, },
        { 0, 1, 0, 1, 149, 76, },
-       { 2, 1, 0, 1, 149, -128, },
+       { 2, 1, 0, 1, 149, 54, },
        { 1, 1, 0, 1, 149, 127, },
        { 3, 1, 0, 1, 149, 76, },
        { 4, 1, 0, 1, 149, 74, },
@@ -40871,9 +40871,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 1, 149, 76, },
        { 7, 1, 0, 1, 149, 54, },
        { 8, 1, 0, 1, 149, 76, },
-       { 9, 1, 0, 1, 149, -128, },
+       { 9, 1, 0, 1, 149, 54, },
        { 0, 1, 0, 1, 153, 76, },
-       { 2, 1, 0, 1, 153, -128, },
+       { 2, 1, 0, 1, 153, 54, },
        { 1, 1, 0, 1, 153, 127, },
        { 3, 1, 0, 1, 153, 76, },
        { 4, 1, 0, 1, 153, 74, },
@@ -40881,9 +40881,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 1, 153, 76, },
        { 7, 1, 0, 1, 153, 54, },
        { 8, 1, 0, 1, 153, 76, },
-       { 9, 1, 0, 1, 153, -128, },
+       { 9, 1, 0, 1, 153, 54, },
        { 0, 1, 0, 1, 157, 76, },
-       { 2, 1, 0, 1, 157, -128, },
+       { 2, 1, 0, 1, 157, 54, },
        { 1, 1, 0, 1, 157, 127, },
        { 3, 1, 0, 1, 157, 76, },
        { 4, 1, 0, 1, 157, 74, },
@@ -40891,9 +40891,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 1, 157, 76, },
        { 7, 1, 0, 1, 157, 54, },
        { 8, 1, 0, 1, 157, 76, },
-       { 9, 1, 0, 1, 157, -128, },
+       { 9, 1, 0, 1, 157, 54, },
        { 0, 1, 0, 1, 161, 76, },
-       { 2, 1, 0, 1, 161, -128, },
+       { 2, 1, 0, 1, 161, 54, },
        { 1, 1, 0, 1, 161, 127, },
        { 3, 1, 0, 1, 161, 76, },
        { 4, 1, 0, 1, 161, 74, },
@@ -40901,9 +40901,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 1, 161, 76, },
        { 7, 1, 0, 1, 161, 54, },
        { 8, 1, 0, 1, 161, 76, },
-       { 9, 1, 0, 1, 161, -128, },
+       { 9, 1, 0, 1, 161, 54, },
        { 0, 1, 0, 1, 165, 76, },
-       { 2, 1, 0, 1, 165, -128, },
+       { 2, 1, 0, 1, 165, 54, },
        { 1, 1, 0, 1, 165, 127, },
        { 3, 1, 0, 1, 165, 76, },
        { 4, 1, 0, 1, 165, 74, },
@@ -40911,7 +40911,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 1, 165, 76, },
        { 7, 1, 0, 1, 165, 54, },
        { 8, 1, 0, 1, 165, 76, },
-       { 9, 1, 0, 1, 165, -128, },
+       { 9, 1, 0, 1, 165, 54, },
        { 0, 1, 0, 2, 36, 72, },
        { 2, 1, 0, 2, 36, 62, },
        { 1, 1, 0, 2, 36, 62, },
@@ -41113,7 +41113,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 8, 1, 0, 2, 144, 76, },
        { 9, 1, 0, 2, 144, 127, },
        { 0, 1, 0, 2, 149, 76, },
-       { 2, 1, 0, 2, 149, -128, },
+       { 2, 1, 0, 2, 149, 54, },
        { 1, 1, 0, 2, 149, 127, },
        { 3, 1, 0, 2, 149, 76, },
        { 4, 1, 0, 2, 149, 74, },
@@ -41121,9 +41121,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 2, 149, 76, },
        { 7, 1, 0, 2, 149, 54, },
        { 8, 1, 0, 2, 149, 76, },
-       { 9, 1, 0, 2, 149, -128, },
+       { 9, 1, 0, 2, 149, 54, },
        { 0, 1, 0, 2, 153, 76, },
-       { 2, 1, 0, 2, 153, -128, },
+       { 2, 1, 0, 2, 153, 54, },
        { 1, 1, 0, 2, 153, 127, },
        { 3, 1, 0, 2, 153, 76, },
        { 4, 1, 0, 2, 153, 74, },
@@ -41131,9 +41131,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 2, 153, 76, },
        { 7, 1, 0, 2, 153, 54, },
        { 8, 1, 0, 2, 153, 76, },
-       { 9, 1, 0, 2, 153, -128, },
+       { 9, 1, 0, 2, 153, 54, },
        { 0, 1, 0, 2, 157, 76, },
-       { 2, 1, 0, 2, 157, -128, },
+       { 2, 1, 0, 2, 157, 54, },
        { 1, 1, 0, 2, 157, 127, },
        { 3, 1, 0, 2, 157, 76, },
        { 4, 1, 0, 2, 157, 74, },
@@ -41141,9 +41141,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 2, 157, 76, },
        { 7, 1, 0, 2, 157, 54, },
        { 8, 1, 0, 2, 157, 76, },
-       { 9, 1, 0, 2, 157, -128, },
+       { 9, 1, 0, 2, 157, 54, },
        { 0, 1, 0, 2, 161, 76, },
-       { 2, 1, 0, 2, 161, -128, },
+       { 2, 1, 0, 2, 161, 54, },
        { 1, 1, 0, 2, 161, 127, },
        { 3, 1, 0, 2, 161, 76, },
        { 4, 1, 0, 2, 161, 74, },
@@ -41151,9 +41151,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 2, 161, 76, },
        { 7, 1, 0, 2, 161, 54, },
        { 8, 1, 0, 2, 161, 76, },
-       { 9, 1, 0, 2, 161, -128, },
+       { 9, 1, 0, 2, 161, 54, },
        { 0, 1, 0, 2, 165, 76, },
-       { 2, 1, 0, 2, 165, -128, },
+       { 2, 1, 0, 2, 165, 54, },
        { 1, 1, 0, 2, 165, 127, },
        { 3, 1, 0, 2, 165, 76, },
        { 4, 1, 0, 2, 165, 74, },
@@ -41161,7 +41161,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 2, 165, 76, },
        { 7, 1, 0, 2, 165, 54, },
        { 8, 1, 0, 2, 165, 76, },
-       { 9, 1, 0, 2, 165, -128, },
+       { 9, 1, 0, 2, 165, 54, },
        { 0, 1, 0, 3, 36, 68, },
        { 2, 1, 0, 3, 36, 38, },
        { 1, 1, 0, 3, 36, 50, },
@@ -41363,7 +41363,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 8, 1, 0, 3, 144, 68, },
        { 9, 1, 0, 3, 144, 127, },
        { 0, 1, 0, 3, 149, 76, },
-       { 2, 1, 0, 3, 149, -128, },
+       { 2, 1, 0, 3, 149, 30, },
        { 1, 1, 0, 3, 149, 127, },
        { 3, 1, 0, 3, 149, 76, },
        { 4, 1, 0, 3, 149, 60, },
@@ -41371,9 +41371,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 3, 149, 76, },
        { 7, 1, 0, 3, 149, 30, },
        { 8, 1, 0, 3, 149, 72, },
-       { 9, 1, 0, 3, 149, -128, },
+       { 9, 1, 0, 3, 149, 30, },
        { 0, 1, 0, 3, 153, 76, },
-       { 2, 1, 0, 3, 153, -128, },
+       { 2, 1, 0, 3, 153, 30, },
        { 1, 1, 0, 3, 153, 127, },
        { 3, 1, 0, 3, 153, 76, },
        { 4, 1, 0, 3, 153, 60, },
@@ -41381,9 +41381,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 3, 153, 76, },
        { 7, 1, 0, 3, 153, 30, },
        { 8, 1, 0, 3, 153, 76, },
-       { 9, 1, 0, 3, 153, -128, },
+       { 9, 1, 0, 3, 153, 30, },
        { 0, 1, 0, 3, 157, 76, },
-       { 2, 1, 0, 3, 157, -128, },
+       { 2, 1, 0, 3, 157, 30, },
        { 1, 1, 0, 3, 157, 127, },
        { 3, 1, 0, 3, 157, 76, },
        { 4, 1, 0, 3, 157, 60, },
@@ -41391,9 +41391,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 3, 157, 76, },
        { 7, 1, 0, 3, 157, 30, },
        { 8, 1, 0, 3, 157, 76, },
-       { 9, 1, 0, 3, 157, -128, },
+       { 9, 1, 0, 3, 157, 30, },
        { 0, 1, 0, 3, 161, 76, },
-       { 2, 1, 0, 3, 161, -128, },
+       { 2, 1, 0, 3, 161, 30, },
        { 1, 1, 0, 3, 161, 127, },
        { 3, 1, 0, 3, 161, 76, },
        { 4, 1, 0, 3, 161, 60, },
@@ -41401,9 +41401,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 3, 161, 76, },
        { 7, 1, 0, 3, 161, 30, },
        { 8, 1, 0, 3, 161, 76, },
-       { 9, 1, 0, 3, 161, -128, },
+       { 9, 1, 0, 3, 161, 30, },
        { 0, 1, 0, 3, 165, 76, },
-       { 2, 1, 0, 3, 165, -128, },
+       { 2, 1, 0, 3, 165, 30, },
        { 1, 1, 0, 3, 165, 127, },
        { 3, 1, 0, 3, 165, 76, },
        { 4, 1, 0, 3, 165, 60, },
@@ -41411,7 +41411,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 0, 3, 165, 76, },
        { 7, 1, 0, 3, 165, 30, },
        { 8, 1, 0, 3, 165, 76, },
-       { 9, 1, 0, 3, 165, -128, },
+       { 9, 1, 0, 3, 165, 30, },
        { 0, 1, 1, 2, 38, 66, },
        { 2, 1, 1, 2, 38, 64, },
        { 1, 1, 1, 2, 38, 62, },
@@ -41513,7 +41513,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 8, 1, 1, 2, 142, 72, },
        { 9, 1, 1, 2, 142, 127, },
        { 0, 1, 1, 2, 151, 72, },
-       { 2, 1, 1, 2, 151, -128, },
+       { 2, 1, 1, 2, 151, 54, },
        { 1, 1, 1, 2, 151, 127, },
        { 3, 1, 1, 2, 151, 72, },
        { 4, 1, 1, 2, 151, 72, },
@@ -41521,9 +41521,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 1, 2, 151, 72, },
        { 7, 1, 1, 2, 151, 54, },
        { 8, 1, 1, 2, 151, 72, },
-       { 9, 1, 1, 2, 151, -128, },
+       { 9, 1, 1, 2, 151, 54, },
        { 0, 1, 1, 2, 159, 72, },
-       { 2, 1, 1, 2, 159, -128, },
+       { 2, 1, 1, 2, 159, 54, },
        { 1, 1, 1, 2, 159, 127, },
        { 3, 1, 1, 2, 159, 72, },
        { 4, 1, 1, 2, 159, 72, },
@@ -41531,7 +41531,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 1, 2, 159, 72, },
        { 7, 1, 1, 2, 159, 54, },
        { 8, 1, 1, 2, 159, 72, },
-       { 9, 1, 1, 2, 159, -128, },
+       { 9, 1, 1, 2, 159, 54, },
        { 0, 1, 1, 3, 38, 60, },
        { 2, 1, 1, 3, 38, 40, },
        { 1, 1, 1, 3, 38, 50, },
@@ -41633,7 +41633,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 8, 1, 1, 3, 142, 68, },
        { 9, 1, 1, 3, 142, 127, },
        { 0, 1, 1, 3, 151, 72, },
-       { 2, 1, 1, 3, 151, -128, },
+       { 2, 1, 1, 3, 151, 30, },
        { 1, 1, 1, 3, 151, 127, },
        { 3, 1, 1, 3, 151, 72, },
        { 4, 1, 1, 3, 151, 66, },
@@ -41641,9 +41641,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 1, 3, 151, 72, },
        { 7, 1, 1, 3, 151, 30, },
        { 8, 1, 1, 3, 151, 68, },
-       { 9, 1, 1, 3, 151, -128, },
+       { 9, 1, 1, 3, 151, 30, },
        { 0, 1, 1, 3, 159, 72, },
-       { 2, 1, 1, 3, 159, -128, },
+       { 2, 1, 1, 3, 159, 30, },
        { 1, 1, 1, 3, 159, 127, },
        { 3, 1, 1, 3, 159, 72, },
        { 4, 1, 1, 3, 159, 66, },
@@ -41651,7 +41651,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 1, 3, 159, 72, },
        { 7, 1, 1, 3, 159, 30, },
        { 8, 1, 1, 3, 159, 72, },
-       { 9, 1, 1, 3, 159, -128, },
+       { 9, 1, 1, 3, 159, 30, },
        { 0, 1, 2, 4, 42, 64, },
        { 2, 1, 2, 4, 42, 64, },
        { 1, 1, 2, 4, 42, 64, },
@@ -41703,7 +41703,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 8, 1, 2, 4, 138, 72, },
        { 9, 1, 2, 4, 138, 127, },
        { 0, 1, 2, 4, 155, 72, },
-       { 2, 1, 2, 4, 155, -128, },
+       { 2, 1, 2, 4, 155, 54, },
        { 1, 1, 2, 4, 155, 127, },
        { 3, 1, 2, 4, 155, 72, },
        { 4, 1, 2, 4, 155, 68, },
@@ -41711,7 +41711,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 2, 4, 155, 72, },
        { 7, 1, 2, 4, 155, 54, },
        { 8, 1, 2, 4, 155, 68, },
-       { 9, 1, 2, 4, 155, -128, },
+       { 9, 1, 2, 4, 155, 54, },
        { 0, 1, 2, 5, 42, 54, },
        { 2, 1, 2, 5, 42, 40, },
        { 1, 1, 2, 5, 42, 50, },
@@ -41763,7 +41763,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 8, 1, 2, 5, 138, 66, },
        { 9, 1, 2, 5, 138, 127, },
        { 0, 1, 2, 5, 155, 62, },
-       { 2, 1, 2, 5, 155, -128, },
+       { 2, 1, 2, 5, 155, 30, },
        { 1, 1, 2, 5, 155, 127, },
        { 3, 1, 2, 5, 155, 62, },
        { 4, 1, 2, 5, 155, 58, },
@@ -41771,145 +41771,145 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type0[] = {
        { 6, 1, 2, 5, 155, 62, },
        { 7, 1, 2, 5, 155, 30, },
        { 8, 1, 2, 5, 155, 62, },
-       { 9, 1, 2, 5, 155, -128, },
+       { 9, 1, 2, 5, 155, 30, },
 };
 
 RTW_DECL_TABLE_TXPWR_LMT(rtw8822c_txpwr_lmt_type0);
 
 static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 0, 0, 0, 0, 1, 72, },
-       { 2, 0, 0, 0, 1, 60, },
-       { 1, 0, 0, 0, 1, 68, },
+       { 2, 0, 0, 0, 1, 56, },
+       { 1, 0, 0, 0, 1, 72, },
        { 3, 0, 0, 0, 1, 72, },
        { 4, 0, 0, 0, 1, 76, },
-       { 5, 0, 0, 0, 1, 60, },
+       { 5, 0, 0, 0, 1, 56, },
        { 6, 0, 0, 0, 1, 72, },
        { 7, 0, 0, 0, 1, 60, },
        { 8, 0, 0, 0, 1, 72, },
        { 9, 0, 0, 0, 1, 60, },
        { 0, 0, 0, 0, 2, 72, },
-       { 2, 0, 0, 0, 2, 60, },
-       { 1, 0, 0, 0, 2, 68, },
+       { 2, 0, 0, 0, 2, 56, },
+       { 1, 0, 0, 0, 2, 72, },
        { 3, 0, 0, 0, 2, 72, },
        { 4, 0, 0, 0, 2, 76, },
-       { 5, 0, 0, 0, 2, 60, },
+       { 5, 0, 0, 0, 2, 56, },
        { 6, 0, 0, 0, 2, 72, },
        { 7, 0, 0, 0, 2, 60, },
        { 8, 0, 0, 0, 2, 72, },
        { 9, 0, 0, 0, 2, 60, },
        { 0, 0, 0, 0, 3, 76, },
-       { 2, 0, 0, 0, 3, 60, },
-       { 1, 0, 0, 0, 3, 68, },
+       { 2, 0, 0, 0, 3, 56, },
+       { 1, 0, 0, 0, 3, 72, },
        { 3, 0, 0, 0, 3, 76, },
        { 4, 0, 0, 0, 3, 76, },
-       { 5, 0, 0, 0, 3, 60, },
+       { 5, 0, 0, 0, 3, 56, },
        { 6, 0, 0, 0, 3, 76, },
        { 7, 0, 0, 0, 3, 60, },
        { 8, 0, 0, 0, 3, 76, },
        { 9, 0, 0, 0, 3, 60, },
        { 0, 0, 0, 0, 4, 76, },
-       { 2, 0, 0, 0, 4, 60, },
-       { 1, 0, 0, 0, 4, 68, },
+       { 2, 0, 0, 0, 4, 56, },
+       { 1, 0, 0, 0, 4, 72, },
        { 3, 0, 0, 0, 4, 76, },
        { 4, 0, 0, 0, 4, 76, },
-       { 5, 0, 0, 0, 4, 60, },
+       { 5, 0, 0, 0, 4, 56, },
        { 6, 0, 0, 0, 4, 76, },
        { 7, 0, 0, 0, 4, 60, },
        { 8, 0, 0, 0, 4, 76, },
        { 9, 0, 0, 0, 4, 60, },
        { 0, 0, 0, 0, 5, 76, },
-       { 2, 0, 0, 0, 5, 60, },
-       { 1, 0, 0, 0, 5, 68, },
+       { 2, 0, 0, 0, 5, 56, },
+       { 1, 0, 0, 0, 5, 72, },
        { 3, 0, 0, 0, 5, 76, },
        { 4, 0, 0, 0, 5, 76, },
-       { 5, 0, 0, 0, 5, 60, },
+       { 5, 0, 0, 0, 5, 56, },
        { 6, 0, 0, 0, 5, 76, },
        { 7, 0, 0, 0, 5, 60, },
        { 8, 0, 0, 0, 5, 76, },
        { 9, 0, 0, 0, 5, 60, },
        { 0, 0, 0, 0, 6, 76, },
-       { 2, 0, 0, 0, 6, 60, },
-       { 1, 0, 0, 0, 6, 68, },
+       { 2, 0, 0, 0, 6, 56, },
+       { 1, 0, 0, 0, 6, 72, },
        { 3, 0, 0, 0, 6, 76, },
        { 4, 0, 0, 0, 6, 76, },
-       { 5, 0, 0, 0, 6, 60, },
+       { 5, 0, 0, 0, 6, 56, },
        { 6, 0, 0, 0, 6, 76, },
        { 7, 0, 0, 0, 6, 60, },
        { 8, 0, 0, 0, 6, 76, },
        { 9, 0, 0, 0, 6, 60, },
        { 0, 0, 0, 0, 7, 76, },
-       { 2, 0, 0, 0, 7, 60, },
-       { 1, 0, 0, 0, 7, 68, },
+       { 2, 0, 0, 0, 7, 56, },
+       { 1, 0, 0, 0, 7, 72, },
        { 3, 0, 0, 0, 7, 76, },
        { 4, 0, 0, 0, 7, 76, },
-       { 5, 0, 0, 0, 7, 60, },
+       { 5, 0, 0, 0, 7, 56, },
        { 6, 0, 0, 0, 7, 76, },
        { 7, 0, 0, 0, 7, 60, },
        { 8, 0, 0, 0, 7, 76, },
        { 9, 0, 0, 0, 7, 60, },
        { 0, 0, 0, 0, 8, 76, },
-       { 2, 0, 0, 0, 8, 60, },
-       { 1, 0, 0, 0, 8, 68, },
+       { 2, 0, 0, 0, 8, 56, },
+       { 1, 0, 0, 0, 8, 72, },
        { 3, 0, 0, 0, 8, 76, },
        { 4, 0, 0, 0, 8, 76, },
-       { 5, 0, 0, 0, 8, 60, },
+       { 5, 0, 0, 0, 8, 56, },
        { 6, 0, 0, 0, 8, 76, },
        { 7, 0, 0, 0, 8, 60, },
        { 8, 0, 0, 0, 8, 76, },
        { 9, 0, 0, 0, 8, 60, },
        { 0, 0, 0, 0, 9, 76, },
-       { 2, 0, 0, 0, 9, 60, },
-       { 1, 0, 0, 0, 9, 68, },
+       { 2, 0, 0, 0, 9, 56, },
+       { 1, 0, 0, 0, 9, 72, },
        { 3, 0, 0, 0, 9, 76, },
        { 4, 0, 0, 0, 9, 76, },
-       { 5, 0, 0, 0, 9, 60, },
+       { 5, 0, 0, 0, 9, 56, },
        { 6, 0, 0, 0, 9, 76, },
        { 7, 0, 0, 0, 9, 60, },
        { 8, 0, 0, 0, 9, 76, },
        { 9, 0, 0, 0, 9, 60, },
        { 0, 0, 0, 0, 10, 72, },
-       { 2, 0, 0, 0, 10, 60, },
-       { 1, 0, 0, 0, 10, 68, },
+       { 2, 0, 0, 0, 10, 56, },
+       { 1, 0, 0, 0, 10, 72, },
        { 3, 0, 0, 0, 10, 72, },
        { 4, 0, 0, 0, 10, 76, },
-       { 5, 0, 0, 0, 10, 60, },
+       { 5, 0, 0, 0, 10, 56, },
        { 6, 0, 0, 0, 10, 72, },
        { 7, 0, 0, 0, 10, 60, },
        { 8, 0, 0, 0, 10, 72, },
        { 9, 0, 0, 0, 10, 60, },
        { 0, 0, 0, 0, 11, 72, },
-       { 2, 0, 0, 0, 11, 60, },
-       { 1, 0, 0, 0, 11, 68, },
+       { 2, 0, 0, 0, 11, 56, },
+       { 1, 0, 0, 0, 11, 72, },
        { 3, 0, 0, 0, 11, 72, },
        { 4, 0, 0, 0, 11, 76, },
-       { 5, 0, 0, 0, 11, 60, },
+       { 5, 0, 0, 0, 11, 56, },
        { 6, 0, 0, 0, 11, 72, },
        { 7, 0, 0, 0, 11, 60, },
        { 8, 0, 0, 0, 11, 72, },
        { 9, 0, 0, 0, 11, 60, },
        { 0, 0, 0, 0, 12, 44, },
-       { 2, 0, 0, 0, 12, 60, },
-       { 1, 0, 0, 0, 12, 68, },
+       { 2, 0, 0, 0, 12, 56, },
+       { 1, 0, 0, 0, 12, 72, },
        { 3, 0, 0, 0, 12, 52, },
        { 4, 0, 0, 0, 12, 76, },
-       { 5, 0, 0, 0, 12, 60, },
+       { 5, 0, 0, 0, 12, 56, },
        { 6, 0, 0, 0, 12, 52, },
        { 7, 0, 0, 0, 12, 60, },
        { 8, 0, 0, 0, 12, 52, },
        { 9, 0, 0, 0, 12, 60, },
        { 0, 0, 0, 0, 13, 40, },
-       { 2, 0, 0, 0, 13, 60, },
-       { 1, 0, 0, 0, 13, 68, },
+       { 2, 0, 0, 0, 13, 56, },
+       { 1, 0, 0, 0, 13, 72, },
        { 3, 0, 0, 0, 13, 48, },
        { 4, 0, 0, 0, 13, 76, },
-       { 5, 0, 0, 0, 13, 60, },
+       { 5, 0, 0, 0, 13, 56, },
        { 6, 0, 0, 0, 13, 48, },
        { 7, 0, 0, 0, 13, 60, },
        { 8, 0, 0, 0, 13, 48, },
        { 9, 0, 0, 0, 13, 60, },
        { 0, 0, 0, 0, 14, 127, },
        { 2, 0, 0, 0, 14, 127, },
-       { 1, 0, 0, 0, 14, 68, },
+       { 1, 0, 0, 0, 14, 72, },
        { 3, 0, 0, 0, 14, 127, },
        { 4, 0, 0, 0, 14, 127, },
        { 5, 0, 0, 0, 14, 127, },
@@ -42041,7 +42041,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 1, 13, 60, },
        { 1, 0, 0, 1, 13, 76, },
        { 3, 0, 0, 1, 13, 28, },
-       { 4, 0, 0, 1, 13, 70, },
+       { 4, 0, 0, 1, 13, 74, },
        { 5, 0, 0, 1, 13, 60, },
        { 6, 0, 0, 1, 13, 28, },
        { 7, 0, 0, 1, 13, 60, },
@@ -42181,7 +42181,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 2, 13, 60, },
        { 1, 0, 0, 2, 13, 76, },
        { 3, 0, 0, 2, 13, 28, },
-       { 4, 0, 0, 2, 13, 72, },
+       { 4, 0, 0, 2, 13, 74, },
        { 5, 0, 0, 2, 13, 60, },
        { 6, 0, 0, 2, 13, 28, },
        { 7, 0, 0, 2, 13, 60, },
@@ -42201,7 +42201,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 1, 36, },
        { 1, 0, 0, 3, 1, 66, },
        { 3, 0, 0, 3, 1, 52, },
-       { 4, 0, 0, 3, 1, 68, },
+       { 4, 0, 0, 3, 1, 72, },
        { 5, 0, 0, 3, 1, 36, },
        { 6, 0, 0, 3, 1, 52, },
        { 7, 0, 0, 3, 1, 36, },
@@ -42211,7 +42211,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 2, 36, },
        { 1, 0, 0, 3, 2, 66, },
        { 3, 0, 0, 3, 2, 60, },
-       { 4, 0, 0, 3, 2, 70, },
+       { 4, 0, 0, 3, 2, 72, },
        { 5, 0, 0, 3, 2, 36, },
        { 6, 0, 0, 3, 2, 60, },
        { 7, 0, 0, 3, 2, 36, },
@@ -42221,7 +42221,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 3, 36, },
        { 1, 0, 0, 3, 3, 66, },
        { 3, 0, 0, 3, 3, 64, },
-       { 4, 0, 0, 3, 3, 70, },
+       { 4, 0, 0, 3, 3, 72, },
        { 5, 0, 0, 3, 3, 36, },
        { 6, 0, 0, 3, 3, 64, },
        { 7, 0, 0, 3, 3, 36, },
@@ -42231,7 +42231,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 4, 36, },
        { 1, 0, 0, 3, 4, 66, },
        { 3, 0, 0, 3, 4, 68, },
-       { 4, 0, 0, 3, 4, 70, },
+       { 4, 0, 0, 3, 4, 72, },
        { 5, 0, 0, 3, 4, 36, },
        { 6, 0, 0, 3, 4, 68, },
        { 7, 0, 0, 3, 4, 36, },
@@ -42241,7 +42241,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 5, 36, },
        { 1, 0, 0, 3, 5, 66, },
        { 3, 0, 0, 3, 5, 76, },
-       { 4, 0, 0, 3, 5, 70, },
+       { 4, 0, 0, 3, 5, 72, },
        { 5, 0, 0, 3, 5, 36, },
        { 6, 0, 0, 3, 5, 76, },
        { 7, 0, 0, 3, 5, 36, },
@@ -42251,7 +42251,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 6, 36, },
        { 1, 0, 0, 3, 6, 66, },
        { 3, 0, 0, 3, 6, 76, },
-       { 4, 0, 0, 3, 6, 70, },
+       { 4, 0, 0, 3, 6, 72, },
        { 5, 0, 0, 3, 6, 36, },
        { 6, 0, 0, 3, 6, 76, },
        { 7, 0, 0, 3, 6, 36, },
@@ -42261,7 +42261,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 7, 36, },
        { 1, 0, 0, 3, 7, 66, },
        { 3, 0, 0, 3, 7, 76, },
-       { 4, 0, 0, 3, 7, 70, },
+       { 4, 0, 0, 3, 7, 72, },
        { 5, 0, 0, 3, 7, 36, },
        { 6, 0, 0, 3, 7, 76, },
        { 7, 0, 0, 3, 7, 36, },
@@ -42271,7 +42271,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 8, 36, },
        { 1, 0, 0, 3, 8, 66, },
        { 3, 0, 0, 3, 8, 68, },
-       { 4, 0, 0, 3, 8, 70, },
+       { 4, 0, 0, 3, 8, 72, },
        { 5, 0, 0, 3, 8, 36, },
        { 6, 0, 0, 3, 8, 68, },
        { 7, 0, 0, 3, 8, 36, },
@@ -42281,7 +42281,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 9, 36, },
        { 1, 0, 0, 3, 9, 66, },
        { 3, 0, 0, 3, 9, 64, },
-       { 4, 0, 0, 3, 9, 70, },
+       { 4, 0, 0, 3, 9, 72, },
        { 5, 0, 0, 3, 9, 36, },
        { 6, 0, 0, 3, 9, 64, },
        { 7, 0, 0, 3, 9, 36, },
@@ -42291,7 +42291,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 10, 36, },
        { 1, 0, 0, 3, 10, 66, },
        { 3, 0, 0, 3, 10, 60, },
-       { 4, 0, 0, 3, 10, 70, },
+       { 4, 0, 0, 3, 10, 72, },
        { 5, 0, 0, 3, 10, 36, },
        { 6, 0, 0, 3, 10, 60, },
        { 7, 0, 0, 3, 10, 36, },
@@ -42301,7 +42301,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 11, 36, },
        { 1, 0, 0, 3, 11, 66, },
        { 3, 0, 0, 3, 11, 52, },
-       { 4, 0, 0, 3, 11, 70, },
+       { 4, 0, 0, 3, 11, 72, },
        { 5, 0, 0, 3, 11, 36, },
        { 6, 0, 0, 3, 11, 52, },
        { 7, 0, 0, 3, 11, 36, },
@@ -42311,7 +42311,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 12, 36, },
        { 1, 0, 0, 3, 12, 66, },
        { 3, 0, 0, 3, 12, 40, },
-       { 4, 0, 0, 3, 12, 70, },
+       { 4, 0, 0, 3, 12, 72, },
        { 5, 0, 0, 3, 12, 36, },
        { 6, 0, 0, 3, 12, 40, },
        { 7, 0, 0, 3, 12, 36, },
@@ -42321,7 +42321,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 0, 3, 13, 36, },
        { 1, 0, 0, 3, 13, 66, },
        { 3, 0, 0, 3, 13, 28, },
-       { 4, 0, 0, 3, 13, 62, },
+       { 4, 0, 0, 3, 13, 68, },
        { 5, 0, 0, 3, 13, 36, },
        { 6, 0, 0, 3, 13, 28, },
        { 7, 0, 0, 3, 13, 36, },
@@ -42501,7 +42501,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 0, 1, 3, 3, 36, },
        { 1, 0, 1, 3, 3, 66, },
        { 3, 0, 1, 3, 3, 48, },
-       { 4, 0, 1, 3, 3, 66, },
+       { 4, 0, 1, 3, 3, 68, },
        { 5, 0, 1, 3, 3, 36, },
        { 6, 0, 1, 3, 3, 48, },
        { 7, 0, 1, 3, 3, 36, },
@@ -42618,137 +42618,137 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 0, 1, 3, 14, 127, },
        { 9, 0, 1, 3, 14, 127, },
        { 0, 1, 0, 1, 36, 74, },
-       { 2, 1, 0, 1, 36, 62, },
-       { 1, 1, 0, 1, 36, 60, },
+       { 2, 1, 0, 1, 36, 58, },
+       { 1, 1, 0, 1, 36, 62, },
        { 3, 1, 0, 1, 36, 62, },
-       { 4, 1, 0, 1, 36, 76, },
-       { 5, 1, 0, 1, 36, 62, },
+       { 4, 1, 0, 1, 36, 74, },
+       { 5, 1, 0, 1, 36, 58, },
        { 6, 1, 0, 1, 36, 64, },
        { 7, 1, 0, 1, 36, 54, },
        { 8, 1, 0, 1, 36, 62, },
        { 9, 1, 0, 1, 36, 62, },
        { 0, 1, 0, 1, 40, 76, },
-       { 2, 1, 0, 1, 40, 62, },
+       { 2, 1, 0, 1, 40, 58, },
        { 1, 1, 0, 1, 40, 62, },
        { 3, 1, 0, 1, 40, 62, },
        { 4, 1, 0, 1, 40, 76, },
-       { 5, 1, 0, 1, 40, 62, },
+       { 5, 1, 0, 1, 40, 58, },
        { 6, 1, 0, 1, 40, 64, },
        { 7, 1, 0, 1, 40, 54, },
        { 8, 1, 0, 1, 40, 62, },
        { 9, 1, 0, 1, 40, 62, },
        { 0, 1, 0, 1, 44, 76, },
-       { 2, 1, 0, 1, 44, 62, },
+       { 2, 1, 0, 1, 44, 58, },
        { 1, 1, 0, 1, 44, 62, },
        { 3, 1, 0, 1, 44, 62, },
        { 4, 1, 0, 1, 44, 76, },
-       { 5, 1, 0, 1, 44, 62, },
+       { 5, 1, 0, 1, 44, 58, },
        { 6, 1, 0, 1, 44, 64, },
        { 7, 1, 0, 1, 44, 54, },
        { 8, 1, 0, 1, 44, 62, },
        { 9, 1, 0, 1, 44, 62, },
        { 0, 1, 0, 1, 48, 76, },
-       { 2, 1, 0, 1, 48, 62, },
+       { 2, 1, 0, 1, 48, 58, },
        { 1, 1, 0, 1, 48, 62, },
        { 3, 1, 0, 1, 48, 62, },
-       { 4, 1, 0, 1, 48, 54, },
-       { 5, 1, 0, 1, 48, 62, },
+       { 4, 1, 0, 1, 48, 58, },
+       { 5, 1, 0, 1, 48, 58, },
        { 6, 1, 0, 1, 48, 64, },
        { 7, 1, 0, 1, 48, 54, },
        { 8, 1, 0, 1, 48, 62, },
        { 9, 1, 0, 1, 48, 62, },
        { 0, 1, 0, 1, 52, 76, },
-       { 2, 1, 0, 1, 52, 62, },
+       { 2, 1, 0, 1, 52, 58, },
        { 1, 1, 0, 1, 52, 62, },
        { 3, 1, 0, 1, 52, 64, },
        { 4, 1, 0, 1, 52, 76, },
-       { 5, 1, 0, 1, 52, 62, },
+       { 5, 1, 0, 1, 52, 58, },
        { 6, 1, 0, 1, 52, 76, },
        { 7, 1, 0, 1, 52, 54, },
        { 8, 1, 0, 1, 52, 76, },
        { 9, 1, 0, 1, 52, 62, },
        { 0, 1, 0, 1, 56, 76, },
-       { 2, 1, 0, 1, 56, 62, },
+       { 2, 1, 0, 1, 56, 58, },
        { 1, 1, 0, 1, 56, 62, },
        { 3, 1, 0, 1, 56, 64, },
        { 4, 1, 0, 1, 56, 76, },
-       { 5, 1, 0, 1, 56, 62, },
+       { 5, 1, 0, 1, 56, 58, },
        { 6, 1, 0, 1, 56, 76, },
        { 7, 1, 0, 1, 56, 54, },
        { 8, 1, 0, 1, 56, 76, },
        { 9, 1, 0, 1, 56, 62, },
        { 0, 1, 0, 1, 60, 76, },
-       { 2, 1, 0, 1, 60, 62, },
+       { 2, 1, 0, 1, 60, 58, },
        { 1, 1, 0, 1, 60, 62, },
        { 3, 1, 0, 1, 60, 64, },
        { 4, 1, 0, 1, 60, 76, },
-       { 5, 1, 0, 1, 60, 62, },
+       { 5, 1, 0, 1, 60, 58, },
        { 6, 1, 0, 1, 60, 76, },
        { 7, 1, 0, 1, 60, 54, },
        { 8, 1, 0, 1, 60, 76, },
        { 9, 1, 0, 1, 60, 62, },
-       { 0, 1, 0, 1, 64, 74, },
-       { 2, 1, 0, 1, 64, 62, },
-       { 1, 1, 0, 1, 64, 60, },
+       { 0, 1, 0, 1, 64, 76, },
+       { 2, 1, 0, 1, 64, 58, },
+       { 1, 1, 0, 1, 64, 62, },
        { 3, 1, 0, 1, 64, 64, },
        { 4, 1, 0, 1, 64, 76, },
-       { 5, 1, 0, 1, 64, 62, },
+       { 5, 1, 0, 1, 64, 58, },
        { 6, 1, 0, 1, 64, 74, },
        { 7, 1, 0, 1, 64, 54, },
        { 8, 1, 0, 1, 64, 74, },
        { 9, 1, 0, 1, 64, 62, },
-       { 0, 1, 0, 1, 100, 72, },
-       { 2, 1, 0, 1, 100, 62, },
+       { 0, 1, 0, 1, 100, 68, },
+       { 2, 1, 0, 1, 100, 58, },
        { 1, 1, 0, 1, 100, 76, },
-       { 3, 1, 0, 1, 100, 72, },
+       { 3, 1, 0, 1, 100, 68, },
        { 4, 1, 0, 1, 100, 76, },
-       { 5, 1, 0, 1, 100, 62, },
+       { 5, 1, 0, 1, 100, 58, },
        { 6, 1, 0, 1, 100, 72, },
        { 7, 1, 0, 1, 100, 54, },
        { 8, 1, 0, 1, 100, 72, },
        { 9, 1, 0, 1, 100, 127, },
        { 0, 1, 0, 1, 104, 76, },
-       { 2, 1, 0, 1, 104, 62, },
+       { 2, 1, 0, 1, 104, 58, },
        { 1, 1, 0, 1, 104, 76, },
        { 3, 1, 0, 1, 104, 76, },
        { 4, 1, 0, 1, 104, 76, },
-       { 5, 1, 0, 1, 104, 62, },
+       { 5, 1, 0, 1, 104, 58, },
        { 6, 1, 0, 1, 104, 76, },
        { 7, 1, 0, 1, 104, 54, },
        { 8, 1, 0, 1, 104, 76, },
        { 9, 1, 0, 1, 104, 127, },
        { 0, 1, 0, 1, 108, 76, },
-       { 2, 1, 0, 1, 108, 62, },
+       { 2, 1, 0, 1, 108, 58, },
        { 1, 1, 0, 1, 108, 76, },
        { 3, 1, 0, 1, 108, 76, },
        { 4, 1, 0, 1, 108, 76, },
-       { 5, 1, 0, 1, 108, 62, },
+       { 5, 1, 0, 1, 108, 58, },
        { 6, 1, 0, 1, 108, 76, },
        { 7, 1, 0, 1, 108, 54, },
        { 8, 1, 0, 1, 108, 76, },
        { 9, 1, 0, 1, 108, 127, },
        { 0, 1, 0, 1, 112, 76, },
-       { 2, 1, 0, 1, 112, 62, },
+       { 2, 1, 0, 1, 112, 58, },
        { 1, 1, 0, 1, 112, 76, },
        { 3, 1, 0, 1, 112, 76, },
        { 4, 1, 0, 1, 112, 76, },
-       { 5, 1, 0, 1, 112, 62, },
+       { 5, 1, 0, 1, 112, 58, },
        { 6, 1, 0, 1, 112, 76, },
        { 7, 1, 0, 1, 112, 54, },
        { 8, 1, 0, 1, 112, 76, },
        { 9, 1, 0, 1, 112, 127, },
        { 0, 1, 0, 1, 116, 76, },
-       { 2, 1, 0, 1, 116, 62, },
+       { 2, 1, 0, 1, 116, 58, },
        { 1, 1, 0, 1, 116, 76, },
        { 3, 1, 0, 1, 116, 76, },
        { 4, 1, 0, 1, 116, 76, },
-       { 5, 1, 0, 1, 116, 62, },
+       { 5, 1, 0, 1, 116, 58, },
        { 6, 1, 0, 1, 116, 76, },
        { 7, 1, 0, 1, 116, 54, },
        { 8, 1, 0, 1, 116, 76, },
        { 9, 1, 0, 1, 116, 127, },
        { 0, 1, 0, 1, 120, 76, },
-       { 2, 1, 0, 1, 120, 62, },
+       { 2, 1, 0, 1, 120, 58, },
        { 1, 1, 0, 1, 120, 76, },
        { 3, 1, 0, 1, 120, 127, },
        { 4, 1, 0, 1, 120, 76, },
@@ -42758,7 +42758,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 0, 1, 120, 76, },
        { 9, 1, 0, 1, 120, 127, },
        { 0, 1, 0, 1, 124, 76, },
-       { 2, 1, 0, 1, 124, 62, },
+       { 2, 1, 0, 1, 124, 58, },
        { 1, 1, 0, 1, 124, 76, },
        { 3, 1, 0, 1, 124, 127, },
        { 4, 1, 0, 1, 124, 76, },
@@ -42768,7 +42768,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 0, 1, 124, 76, },
        { 9, 1, 0, 1, 124, 127, },
        { 0, 1, 0, 1, 128, 76, },
-       { 2, 1, 0, 1, 128, 62, },
+       { 2, 1, 0, 1, 128, 58, },
        { 1, 1, 0, 1, 128, 76, },
        { 3, 1, 0, 1, 128, 127, },
        { 4, 1, 0, 1, 128, 76, },
@@ -42778,38 +42778,38 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 0, 1, 128, 76, },
        { 9, 1, 0, 1, 128, 127, },
        { 0, 1, 0, 1, 132, 76, },
-       { 2, 1, 0, 1, 132, 62, },
+       { 2, 1, 0, 1, 132, 58, },
        { 1, 1, 0, 1, 132, 76, },
        { 3, 1, 0, 1, 132, 76, },
        { 4, 1, 0, 1, 132, 76, },
-       { 5, 1, 0, 1, 132, 62, },
+       { 5, 1, 0, 1, 132, 58, },
        { 6, 1, 0, 1, 132, 76, },
        { 7, 1, 0, 1, 132, 54, },
        { 8, 1, 0, 1, 132, 76, },
        { 9, 1, 0, 1, 132, 127, },
        { 0, 1, 0, 1, 136, 76, },
-       { 2, 1, 0, 1, 136, 62, },
+       { 2, 1, 0, 1, 136, 58, },
        { 1, 1, 0, 1, 136, 76, },
        { 3, 1, 0, 1, 136, 76, },
        { 4, 1, 0, 1, 136, 76, },
-       { 5, 1, 0, 1, 136, 62, },
+       { 5, 1, 0, 1, 136, 58, },
        { 6, 1, 0, 1, 136, 76, },
        { 7, 1, 0, 1, 136, 54, },
        { 8, 1, 0, 1, 136, 76, },
        { 9, 1, 0, 1, 136, 127, },
-       { 0, 1, 0, 1, 140, 72, },
-       { 2, 1, 0, 1, 140, 62, },
+       { 0, 1, 0, 1, 140, 74, },
+       { 2, 1, 0, 1, 140, 58, },
        { 1, 1, 0, 1, 140, 76, },
-       { 3, 1, 0, 1, 140, 72, },
+       { 3, 1, 0, 1, 140, 74, },
        { 4, 1, 0, 1, 140, 76, },
-       { 5, 1, 0, 1, 140, 62, },
+       { 5, 1, 0, 1, 140, 58, },
        { 6, 1, 0, 1, 140, 72, },
        { 7, 1, 0, 1, 140, 54, },
        { 8, 1, 0, 1, 140, 72, },
        { 9, 1, 0, 1, 140, 127, },
        { 0, 1, 0, 1, 144, 76, },
        { 2, 1, 0, 1, 144, 127, },
-       { 1, 1, 0, 1, 144, 127, },
+       { 1, 1, 0, 1, 144, 76, },
        { 3, 1, 0, 1, 144, 76, },
        { 4, 1, 0, 1, 144, 76, },
        { 5, 1, 0, 1, 144, 127, },
@@ -42818,7 +42818,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 0, 1, 144, 76, },
        { 9, 1, 0, 1, 144, 127, },
        { 0, 1, 0, 1, 149, 76, },
-       { 2, 1, 0, 1, 149, -128, },
+       { 2, 1, 0, 1, 149, 28, },
        { 1, 1, 0, 1, 149, 127, },
        { 3, 1, 0, 1, 149, 76, },
        { 4, 1, 0, 1, 149, 74, },
@@ -42826,9 +42826,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 1, 149, 76, },
        { 7, 1, 0, 1, 149, 54, },
        { 8, 1, 0, 1, 149, 76, },
-       { 9, 1, 0, 1, 149, -128, },
+       { 9, 1, 0, 1, 149, 28, },
        { 0, 1, 0, 1, 153, 76, },
-       { 2, 1, 0, 1, 153, -128, },
+       { 2, 1, 0, 1, 153, 28, },
        { 1, 1, 0, 1, 153, 127, },
        { 3, 1, 0, 1, 153, 76, },
        { 4, 1, 0, 1, 153, 74, },
@@ -42836,9 +42836,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 1, 153, 76, },
        { 7, 1, 0, 1, 153, 54, },
        { 8, 1, 0, 1, 153, 76, },
-       { 9, 1, 0, 1, 153, -128, },
+       { 9, 1, 0, 1, 153, 28, },
        { 0, 1, 0, 1, 157, 76, },
-       { 2, 1, 0, 1, 157, -128, },
+       { 2, 1, 0, 1, 157, 28, },
        { 1, 1, 0, 1, 157, 127, },
        { 3, 1, 0, 1, 157, 76, },
        { 4, 1, 0, 1, 157, 74, },
@@ -42846,9 +42846,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 1, 157, 76, },
        { 7, 1, 0, 1, 157, 54, },
        { 8, 1, 0, 1, 157, 76, },
-       { 9, 1, 0, 1, 157, -128, },
+       { 9, 1, 0, 1, 157, 28, },
        { 0, 1, 0, 1, 161, 76, },
-       { 2, 1, 0, 1, 161, -128, },
+       { 2, 1, 0, 1, 161, 28, },
        { 1, 1, 0, 1, 161, 127, },
        { 3, 1, 0, 1, 161, 76, },
        { 4, 1, 0, 1, 161, 74, },
@@ -42856,9 +42856,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 1, 161, 76, },
        { 7, 1, 0, 1, 161, 54, },
        { 8, 1, 0, 1, 161, 76, },
-       { 9, 1, 0, 1, 161, -128, },
+       { 9, 1, 0, 1, 161, 28, },
        { 0, 1, 0, 1, 165, 76, },
-       { 2, 1, 0, 1, 165, -128, },
+       { 2, 1, 0, 1, 165, 28, },
        { 1, 1, 0, 1, 165, 127, },
        { 3, 1, 0, 1, 165, 76, },
        { 4, 1, 0, 1, 165, 74, },
@@ -42866,139 +42866,139 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 1, 165, 76, },
        { 7, 1, 0, 1, 165, 54, },
        { 8, 1, 0, 1, 165, 76, },
-       { 9, 1, 0, 1, 165, -128, },
-       { 0, 1, 0, 2, 36, 72, },
-       { 2, 1, 0, 2, 36, 62, },
-       { 1, 1, 0, 2, 36, 62, },
+       { 9, 1, 0, 1, 165, 28, },
+       { 0, 1, 0, 2, 36, 70, },
+       { 2, 1, 0, 2, 36, 58, },
+       { 1, 1, 0, 2, 36, 64, },
        { 3, 1, 0, 2, 36, 62, },
        { 4, 1, 0, 2, 36, 76, },
-       { 5, 1, 0, 2, 36, 62, },
+       { 5, 1, 0, 2, 36, 58, },
        { 6, 1, 0, 2, 36, 64, },
        { 7, 1, 0, 2, 36, 54, },
        { 8, 1, 0, 2, 36, 62, },
        { 9, 1, 0, 2, 36, 62, },
        { 0, 1, 0, 2, 40, 76, },
-       { 2, 1, 0, 2, 40, 62, },
+       { 2, 1, 0, 2, 40, 58, },
        { 1, 1, 0, 2, 40, 62, },
        { 3, 1, 0, 2, 40, 62, },
        { 4, 1, 0, 2, 40, 76, },
-       { 5, 1, 0, 2, 40, 62, },
+       { 5, 1, 0, 2, 40, 58, },
        { 6, 1, 0, 2, 40, 64, },
        { 7, 1, 0, 2, 40, 54, },
        { 8, 1, 0, 2, 40, 62, },
        { 9, 1, 0, 2, 40, 62, },
        { 0, 1, 0, 2, 44, 76, },
-       { 2, 1, 0, 2, 44, 62, },
+       { 2, 1, 0, 2, 44, 58, },
        { 1, 1, 0, 2, 44, 62, },
        { 3, 1, 0, 2, 44, 62, },
        { 4, 1, 0, 2, 44, 76, },
-       { 5, 1, 0, 2, 44, 62, },
+       { 5, 1, 0, 2, 44, 58, },
        { 6, 1, 0, 2, 44, 64, },
        { 7, 1, 0, 2, 44, 54, },
        { 8, 1, 0, 2, 44, 62, },
        { 9, 1, 0, 2, 44, 62, },
        { 0, 1, 0, 2, 48, 76, },
-       { 2, 1, 0, 2, 48, 62, },
+       { 2, 1, 0, 2, 48, 58, },
        { 1, 1, 0, 2, 48, 62, },
        { 3, 1, 0, 2, 48, 62, },
-       { 4, 1, 0, 2, 48, 54, },
-       { 5, 1, 0, 2, 48, 62, },
+       { 4, 1, 0, 2, 48, 58, },
+       { 5, 1, 0, 2, 48, 58, },
        { 6, 1, 0, 2, 48, 64, },
        { 7, 1, 0, 2, 48, 54, },
        { 8, 1, 0, 2, 48, 62, },
        { 9, 1, 0, 2, 48, 62, },
        { 0, 1, 0, 2, 52, 76, },
-       { 2, 1, 0, 2, 52, 62, },
+       { 2, 1, 0, 2, 52, 58, },
        { 1, 1, 0, 2, 52, 62, },
        { 3, 1, 0, 2, 52, 64, },
        { 4, 1, 0, 2, 52, 76, },
-       { 5, 1, 0, 2, 52, 62, },
+       { 5, 1, 0, 2, 52, 58, },
        { 6, 1, 0, 2, 52, 76, },
        { 7, 1, 0, 2, 52, 54, },
        { 8, 1, 0, 2, 52, 76, },
        { 9, 1, 0, 2, 52, 62, },
        { 0, 1, 0, 2, 56, 76, },
-       { 2, 1, 0, 2, 56, 62, },
+       { 2, 1, 0, 2, 56, 58, },
        { 1, 1, 0, 2, 56, 62, },
        { 3, 1, 0, 2, 56, 64, },
        { 4, 1, 0, 2, 56, 76, },
-       { 5, 1, 0, 2, 56, 62, },
+       { 5, 1, 0, 2, 56, 58, },
        { 6, 1, 0, 2, 56, 76, },
        { 7, 1, 0, 2, 56, 54, },
        { 8, 1, 0, 2, 56, 76, },
        { 9, 1, 0, 2, 56, 62, },
        { 0, 1, 0, 2, 60, 76, },
-       { 2, 1, 0, 2, 60, 62, },
+       { 2, 1, 0, 2, 60, 58, },
        { 1, 1, 0, 2, 60, 62, },
        { 3, 1, 0, 2, 60, 64, },
        { 4, 1, 0, 2, 60, 76, },
-       { 5, 1, 0, 2, 60, 62, },
+       { 5, 1, 0, 2, 60, 58, },
        { 6, 1, 0, 2, 60, 76, },
        { 7, 1, 0, 2, 60, 54, },
        { 8, 1, 0, 2, 60, 76, },
        { 9, 1, 0, 2, 60, 62, },
-       { 0, 1, 0, 2, 64, 74, },
-       { 2, 1, 0, 2, 64, 62, },
-       { 1, 1, 0, 2, 64, 60, },
+       { 0, 1, 0, 2, 64, 70, },
+       { 2, 1, 0, 2, 64, 58, },
+       { 1, 1, 0, 2, 64, 62, },
        { 3, 1, 0, 2, 64, 64, },
        { 4, 1, 0, 2, 64, 74, },
-       { 5, 1, 0, 2, 64, 62, },
+       { 5, 1, 0, 2, 64, 58, },
        { 6, 1, 0, 2, 64, 74, },
        { 7, 1, 0, 2, 64, 54, },
        { 8, 1, 0, 2, 64, 74, },
        { 9, 1, 0, 2, 64, 62, },
-       { 0, 1, 0, 2, 100, 70, },
-       { 2, 1, 0, 2, 100, 62, },
+       { 0, 1, 0, 2, 100, 66, },
+       { 2, 1, 0, 2, 100, 58, },
        { 1, 1, 0, 2, 100, 76, },
-       { 3, 1, 0, 2, 100, 70, },
+       { 3, 1, 0, 2, 100, 66, },
        { 4, 1, 0, 2, 100, 76, },
-       { 5, 1, 0, 2, 100, 62, },
+       { 5, 1, 0, 2, 100, 58, },
        { 6, 1, 0, 2, 100, 70, },
        { 7, 1, 0, 2, 100, 54, },
        { 8, 1, 0, 2, 100, 70, },
        { 9, 1, 0, 2, 100, 127, },
        { 0, 1, 0, 2, 104, 76, },
-       { 2, 1, 0, 2, 104, 62, },
+       { 2, 1, 0, 2, 104, 58, },
        { 1, 1, 0, 2, 104, 76, },
        { 3, 1, 0, 2, 104, 76, },
        { 4, 1, 0, 2, 104, 76, },
-       { 5, 1, 0, 2, 104, 62, },
+       { 5, 1, 0, 2, 104, 58, },
        { 6, 1, 0, 2, 104, 76, },
        { 7, 1, 0, 2, 104, 54, },
        { 8, 1, 0, 2, 104, 76, },
        { 9, 1, 0, 2, 104, 127, },
        { 0, 1, 0, 2, 108, 76, },
-       { 2, 1, 0, 2, 108, 62, },
+       { 2, 1, 0, 2, 108, 58, },
        { 1, 1, 0, 2, 108, 76, },
        { 3, 1, 0, 2, 108, 76, },
        { 4, 1, 0, 2, 108, 76, },
-       { 5, 1, 0, 2, 108, 62, },
+       { 5, 1, 0, 2, 108, 58, },
        { 6, 1, 0, 2, 108, 76, },
        { 7, 1, 0, 2, 108, 54, },
        { 8, 1, 0, 2, 108, 76, },
        { 9, 1, 0, 2, 108, 127, },
        { 0, 1, 0, 2, 112, 76, },
-       { 2, 1, 0, 2, 112, 62, },
+       { 2, 1, 0, 2, 112, 58, },
        { 1, 1, 0, 2, 112, 76, },
        { 3, 1, 0, 2, 112, 76, },
        { 4, 1, 0, 2, 112, 76, },
-       { 5, 1, 0, 2, 112, 62, },
+       { 5, 1, 0, 2, 112, 58, },
        { 6, 1, 0, 2, 112, 76, },
        { 7, 1, 0, 2, 112, 54, },
        { 8, 1, 0, 2, 112, 76, },
        { 9, 1, 0, 2, 112, 127, },
        { 0, 1, 0, 2, 116, 76, },
-       { 2, 1, 0, 2, 116, 62, },
+       { 2, 1, 0, 2, 116, 58, },
        { 1, 1, 0, 2, 116, 76, },
        { 3, 1, 0, 2, 116, 76, },
        { 4, 1, 0, 2, 116, 76, },
-       { 5, 1, 0, 2, 116, 62, },
+       { 5, 1, 0, 2, 116, 58, },
        { 6, 1, 0, 2, 116, 76, },
        { 7, 1, 0, 2, 116, 54, },
        { 8, 1, 0, 2, 116, 76, },
        { 9, 1, 0, 2, 116, 127, },
        { 0, 1, 0, 2, 120, 76, },
-       { 2, 1, 0, 2, 120, 62, },
+       { 2, 1, 0, 2, 120, 58, },
        { 1, 1, 0, 2, 120, 76, },
        { 3, 1, 0, 2, 120, 127, },
        { 4, 1, 0, 2, 120, 76, },
@@ -43008,7 +43008,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 0, 2, 120, 76, },
        { 9, 1, 0, 2, 120, 127, },
        { 0, 1, 0, 2, 124, 76, },
-       { 2, 1, 0, 2, 124, 62, },
+       { 2, 1, 0, 2, 124, 58, },
        { 1, 1, 0, 2, 124, 76, },
        { 3, 1, 0, 2, 124, 127, },
        { 4, 1, 0, 2, 124, 76, },
@@ -43018,7 +43018,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 0, 2, 124, 76, },
        { 9, 1, 0, 2, 124, 127, },
        { 0, 1, 0, 2, 128, 76, },
-       { 2, 1, 0, 2, 128, 62, },
+       { 2, 1, 0, 2, 128, 58, },
        { 1, 1, 0, 2, 128, 76, },
        { 3, 1, 0, 2, 128, 127, },
        { 4, 1, 0, 2, 128, 76, },
@@ -43028,38 +43028,38 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 0, 2, 128, 76, },
        { 9, 1, 0, 2, 128, 127, },
        { 0, 1, 0, 2, 132, 76, },
-       { 2, 1, 0, 2, 132, 62, },
+       { 2, 1, 0, 2, 132, 58, },
        { 1, 1, 0, 2, 132, 76, },
        { 3, 1, 0, 2, 132, 76, },
        { 4, 1, 0, 2, 132, 76, },
-       { 5, 1, 0, 2, 132, 62, },
+       { 5, 1, 0, 2, 132, 58, },
        { 6, 1, 0, 2, 132, 76, },
        { 7, 1, 0, 2, 132, 54, },
        { 8, 1, 0, 2, 132, 76, },
        { 9, 1, 0, 2, 132, 127, },
        { 0, 1, 0, 2, 136, 76, },
-       { 2, 1, 0, 2, 136, 62, },
+       { 2, 1, 0, 2, 136, 58, },
        { 1, 1, 0, 2, 136, 76, },
        { 3, 1, 0, 2, 136, 76, },
        { 4, 1, 0, 2, 136, 76, },
-       { 5, 1, 0, 2, 136, 62, },
+       { 5, 1, 0, 2, 136, 58, },
        { 6, 1, 0, 2, 136, 76, },
        { 7, 1, 0, 2, 136, 54, },
        { 8, 1, 0, 2, 136, 76, },
        { 9, 1, 0, 2, 136, 127, },
-       { 0, 1, 0, 2, 140, 70, },
-       { 2, 1, 0, 2, 140, 62, },
+       { 0, 1, 0, 2, 140, 66, },
+       { 2, 1, 0, 2, 140, 58, },
        { 1, 1, 0, 2, 140, 76, },
-       { 3, 1, 0, 2, 140, 70, },
+       { 3, 1, 0, 2, 140, 66, },
        { 4, 1, 0, 2, 140, 76, },
-       { 5, 1, 0, 2, 140, 62, },
+       { 5, 1, 0, 2, 140, 58, },
        { 6, 1, 0, 2, 140, 70, },
        { 7, 1, 0, 2, 140, 54, },
        { 8, 1, 0, 2, 140, 70, },
        { 9, 1, 0, 2, 140, 127, },
        { 0, 1, 0, 2, 144, 76, },
        { 2, 1, 0, 2, 144, 127, },
-       { 1, 1, 0, 2, 144, 127, },
+       { 1, 1, 0, 2, 144, 76, },
        { 3, 1, 0, 2, 144, 76, },
        { 4, 1, 0, 2, 144, 76, },
        { 5, 1, 0, 2, 144, 127, },
@@ -43068,7 +43068,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 0, 2, 144, 76, },
        { 9, 1, 0, 2, 144, 127, },
        { 0, 1, 0, 2, 149, 76, },
-       { 2, 1, 0, 2, 149, -128, },
+       { 2, 1, 0, 2, 149, 28, },
        { 1, 1, 0, 2, 149, 127, },
        { 3, 1, 0, 2, 149, 76, },
        { 4, 1, 0, 2, 149, 74, },
@@ -43076,9 +43076,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 2, 149, 76, },
        { 7, 1, 0, 2, 149, 54, },
        { 8, 1, 0, 2, 149, 76, },
-       { 9, 1, 0, 2, 149, -128, },
+       { 9, 1, 0, 2, 149, 28, },
        { 0, 1, 0, 2, 153, 76, },
-       { 2, 1, 0, 2, 153, -128, },
+       { 2, 1, 0, 2, 153, 28, },
        { 1, 1, 0, 2, 153, 127, },
        { 3, 1, 0, 2, 153, 76, },
        { 4, 1, 0, 2, 153, 74, },
@@ -43086,9 +43086,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 2, 153, 76, },
        { 7, 1, 0, 2, 153, 54, },
        { 8, 1, 0, 2, 153, 76, },
-       { 9, 1, 0, 2, 153, -128, },
+       { 9, 1, 0, 2, 153, 28, },
        { 0, 1, 0, 2, 157, 76, },
-       { 2, 1, 0, 2, 157, -128, },
+       { 2, 1, 0, 2, 157, 28, },
        { 1, 1, 0, 2, 157, 127, },
        { 3, 1, 0, 2, 157, 76, },
        { 4, 1, 0, 2, 157, 74, },
@@ -43096,9 +43096,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 2, 157, 76, },
        { 7, 1, 0, 2, 157, 54, },
        { 8, 1, 0, 2, 157, 76, },
-       { 9, 1, 0, 2, 157, -128, },
+       { 9, 1, 0, 2, 157, 28, },
        { 0, 1, 0, 2, 161, 76, },
-       { 2, 1, 0, 2, 161, -128, },
+       { 2, 1, 0, 2, 161, 28, },
        { 1, 1, 0, 2, 161, 127, },
        { 3, 1, 0, 2, 161, 76, },
        { 4, 1, 0, 2, 161, 74, },
@@ -43106,9 +43106,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 2, 161, 76, },
        { 7, 1, 0, 2, 161, 54, },
        { 8, 1, 0, 2, 161, 76, },
-       { 9, 1, 0, 2, 161, -128, },
+       { 9, 1, 0, 2, 161, 28, },
        { 0, 1, 0, 2, 165, 76, },
-       { 2, 1, 0, 2, 165, -128, },
+       { 2, 1, 0, 2, 165, 28, },
        { 1, 1, 0, 2, 165, 127, },
        { 3, 1, 0, 2, 165, 76, },
        { 4, 1, 0, 2, 165, 74, },
@@ -43116,262 +43116,262 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 0, 2, 165, 76, },
        { 7, 1, 0, 2, 165, 54, },
        { 8, 1, 0, 2, 165, 76, },
-       { 9, 1, 0, 2, 165, -128, },
-       { 0, 1, 0, 3, 36, 68, },
-       { 2, 1, 0, 3, 36, 38, },
+       { 9, 1, 0, 2, 165, 28, },
+       { 0, 1, 0, 3, 36, 64, },
+       { 2, 1, 0, 3, 36, 36, },
        { 1, 1, 0, 3, 36, 50, },
        { 3, 1, 0, 3, 36, 38, },
        { 4, 1, 0, 3, 36, 66, },
-       { 5, 1, 0, 3, 36, 38, },
+       { 5, 1, 0, 3, 36, 36, },
        { 6, 1, 0, 3, 36, 52, },
        { 7, 1, 0, 3, 36, 30, },
        { 8, 1, 0, 3, 36, 50, },
        { 9, 1, 0, 3, 36, 38, },
        { 0, 1, 0, 3, 40, 68, },
-       { 2, 1, 0, 3, 40, 38, },
+       { 2, 1, 0, 3, 40, 36, },
        { 1, 1, 0, 3, 40, 50, },
        { 3, 1, 0, 3, 40, 38, },
        { 4, 1, 0, 3, 40, 66, },
-       { 5, 1, 0, 3, 40, 38, },
+       { 5, 1, 0, 3, 40, 36, },
        { 6, 1, 0, 3, 40, 52, },
        { 7, 1, 0, 3, 40, 30, },
        { 8, 1, 0, 3, 40, 50, },
        { 9, 1, 0, 3, 40, 38, },
        { 0, 1, 0, 3, 44, 68, },
-       { 2, 1, 0, 3, 44, 38, },
+       { 2, 1, 0, 3, 44, 36, },
        { 1, 1, 0, 3, 44, 50, },
        { 3, 1, 0, 3, 44, 38, },
        { 4, 1, 0, 3, 44, 66, },
-       { 5, 1, 0, 3, 44, 38, },
+       { 5, 1, 0, 3, 44, 36, },
        { 6, 1, 0, 3, 44, 52, },
        { 7, 1, 0, 3, 44, 30, },
        { 8, 1, 0, 3, 44, 50, },
        { 9, 1, 0, 3, 44, 38, },
        { 0, 1, 0, 3, 48, 68, },
-       { 2, 1, 0, 3, 48, 38, },
+       { 2, 1, 0, 3, 48, 36, },
        { 1, 1, 0, 3, 48, 50, },
        { 3, 1, 0, 3, 48, 38, },
-       { 4, 1, 0, 3, 48, 36, },
-       { 5, 1, 0, 3, 48, 38, },
+       { 4, 1, 0, 3, 48, 42, },
+       { 5, 1, 0, 3, 48, 36, },
        { 6, 1, 0, 3, 48, 52, },
        { 7, 1, 0, 3, 48, 30, },
        { 8, 1, 0, 3, 48, 50, },
        { 9, 1, 0, 3, 48, 38, },
        { 0, 1, 0, 3, 52, 68, },
-       { 2, 1, 0, 3, 52, 38, },
+       { 2, 1, 0, 3, 52, 36, },
        { 1, 1, 0, 3, 52, 50, },
        { 3, 1, 0, 3, 52, 40, },
        { 4, 1, 0, 3, 52, 66, },
-       { 5, 1, 0, 3, 52, 38, },
+       { 5, 1, 0, 3, 52, 36, },
        { 6, 1, 0, 3, 52, 68, },
        { 7, 1, 0, 3, 52, 30, },
        { 8, 1, 0, 3, 52, 68, },
        { 9, 1, 0, 3, 52, 38, },
        { 0, 1, 0, 3, 56, 68, },
-       { 2, 1, 0, 3, 56, 38, },
+       { 2, 1, 0, 3, 56, 36, },
        { 1, 1, 0, 3, 56, 50, },
        { 3, 1, 0, 3, 56, 40, },
        { 4, 1, 0, 3, 56, 66, },
-       { 5, 1, 0, 3, 56, 38, },
+       { 5, 1, 0, 3, 56, 36, },
        { 6, 1, 0, 3, 56, 68, },
        { 7, 1, 0, 3, 56, 30, },
        { 8, 1, 0, 3, 56, 68, },
        { 9, 1, 0, 3, 56, 38, },
-       { 0, 1, 0, 3, 60, 66, },
-       { 2, 1, 0, 3, 60, 38, },
+       { 0, 1, 0, 3, 60, 68, },
+       { 2, 1, 0, 3, 60, 36, },
        { 1, 1, 0, 3, 60, 50, },
        { 3, 1, 0, 3, 60, 40, },
        { 4, 1, 0, 3, 60, 66, },
-       { 5, 1, 0, 3, 60, 38, },
+       { 5, 1, 0, 3, 60, 36, },
        { 6, 1, 0, 3, 60, 66, },
        { 7, 1, 0, 3, 60, 30, },
        { 8, 1, 0, 3, 60, 66, },
        { 9, 1, 0, 3, 60, 38, },
-       { 0, 1, 0, 3, 64, 68, },
-       { 2, 1, 0, 3, 64, 38, },
+       { 0, 1, 0, 3, 64, 66, },
+       { 2, 1, 0, 3, 64, 36, },
        { 1, 1, 0, 3, 64, 50, },
        { 3, 1, 0, 3, 64, 40, },
        { 4, 1, 0, 3, 64, 66, },
-       { 5, 1, 0, 3, 64, 38, },
+       { 5, 1, 0, 3, 64, 36, },
        { 6, 1, 0, 3, 64, 68, },
        { 7, 1, 0, 3, 64, 30, },
        { 8, 1, 0, 3, 64, 68, },
        { 9, 1, 0, 3, 64, 38, },
-       { 0, 1, 0, 3, 100, 60, },
-       { 2, 1, 0, 3, 100, 38, },
+       { 0, 1, 0, 3, 100, 64, },
+       { 2, 1, 0, 3, 100, 36, },
        { 1, 1, 0, 3, 100, 70, },
-       { 3, 1, 0, 3, 100, 60, },
-       { 4, 1, 0, 3, 100, 64, },
-       { 5, 1, 0, 3, 100, 38, },
+       { 3, 1, 0, 3, 100, 64, },
+       { 4, 1, 0, 3, 100, 66, },
+       { 5, 1, 0, 3, 100, 36, },
        { 6, 1, 0, 3, 100, 60, },
        { 7, 1, 0, 3, 100, 30, },
        { 8, 1, 0, 3, 100, 60, },
        { 9, 1, 0, 3, 100, 127, },
        { 0, 1, 0, 3, 104, 68, },
-       { 2, 1, 0, 3, 104, 38, },
+       { 2, 1, 0, 3, 104, 36, },
        { 1, 1, 0, 3, 104, 70, },
        { 3, 1, 0, 3, 104, 68, },
-       { 4, 1, 0, 3, 104, 64, },
-       { 5, 1, 0, 3, 104, 38, },
+       { 4, 1, 0, 3, 104, 66, },
+       { 5, 1, 0, 3, 104, 36, },
        { 6, 1, 0, 3, 104, 68, },
        { 7, 1, 0, 3, 104, 30, },
        { 8, 1, 0, 3, 104, 68, },
        { 9, 1, 0, 3, 104, 127, },
        { 0, 1, 0, 3, 108, 68, },
-       { 2, 1, 0, 3, 108, 38, },
+       { 2, 1, 0, 3, 108, 36, },
        { 1, 1, 0, 3, 108, 70, },
        { 3, 1, 0, 3, 108, 68, },
-       { 4, 1, 0, 3, 108, 64, },
-       { 5, 1, 0, 3, 108, 38, },
+       { 4, 1, 0, 3, 108, 66, },
+       { 5, 1, 0, 3, 108, 36, },
        { 6, 1, 0, 3, 108, 68, },
        { 7, 1, 0, 3, 108, 30, },
        { 8, 1, 0, 3, 108, 68, },
        { 9, 1, 0, 3, 108, 127, },
        { 0, 1, 0, 3, 112, 68, },
-       { 2, 1, 0, 3, 112, 38, },
+       { 2, 1, 0, 3, 112, 36, },
        { 1, 1, 0, 3, 112, 70, },
        { 3, 1, 0, 3, 112, 68, },
-       { 4, 1, 0, 3, 112, 64, },
-       { 5, 1, 0, 3, 112, 38, },
+       { 4, 1, 0, 3, 112, 66, },
+       { 5, 1, 0, 3, 112, 36, },
        { 6, 1, 0, 3, 112, 68, },
        { 7, 1, 0, 3, 112, 30, },
        { 8, 1, 0, 3, 112, 68, },
        { 9, 1, 0, 3, 112, 127, },
        { 0, 1, 0, 3, 116, 68, },
-       { 2, 1, 0, 3, 116, 38, },
+       { 2, 1, 0, 3, 116, 36, },
        { 1, 1, 0, 3, 116, 70, },
        { 3, 1, 0, 3, 116, 68, },
-       { 4, 1, 0, 3, 116, 64, },
-       { 5, 1, 0, 3, 116, 38, },
+       { 4, 1, 0, 3, 116, 66, },
+       { 5, 1, 0, 3, 116, 36, },
        { 6, 1, 0, 3, 116, 68, },
        { 7, 1, 0, 3, 116, 30, },
        { 8, 1, 0, 3, 116, 68, },
        { 9, 1, 0, 3, 116, 127, },
        { 0, 1, 0, 3, 120, 68, },
-       { 2, 1, 0, 3, 120, 38, },
+       { 2, 1, 0, 3, 120, 36, },
        { 1, 1, 0, 3, 120, 70, },
        { 3, 1, 0, 3, 120, 127, },
-       { 4, 1, 0, 3, 120, 64, },
+       { 4, 1, 0, 3, 120, 66, },
        { 5, 1, 0, 3, 120, 127, },
        { 6, 1, 0, 3, 120, 68, },
        { 7, 1, 0, 3, 120, 30, },
        { 8, 1, 0, 3, 120, 68, },
        { 9, 1, 0, 3, 120, 127, },
        { 0, 1, 0, 3, 124, 68, },
-       { 2, 1, 0, 3, 124, 38, },
+       { 2, 1, 0, 3, 124, 36, },
        { 1, 1, 0, 3, 124, 70, },
        { 3, 1, 0, 3, 124, 127, },
-       { 4, 1, 0, 3, 124, 64, },
+       { 4, 1, 0, 3, 124, 66, },
        { 5, 1, 0, 3, 124, 127, },
        { 6, 1, 0, 3, 124, 68, },
        { 7, 1, 0, 3, 124, 30, },
        { 8, 1, 0, 3, 124, 68, },
        { 9, 1, 0, 3, 124, 127, },
        { 0, 1, 0, 3, 128, 68, },
-       { 2, 1, 0, 3, 128, 38, },
+       { 2, 1, 0, 3, 128, 36, },
        { 1, 1, 0, 3, 128, 70, },
        { 3, 1, 0, 3, 128, 127, },
-       { 4, 1, 0, 3, 128, 64, },
+       { 4, 1, 0, 3, 128, 66, },
        { 5, 1, 0, 3, 128, 127, },
        { 6, 1, 0, 3, 128, 68, },
        { 7, 1, 0, 3, 128, 30, },
        { 8, 1, 0, 3, 128, 68, },
        { 9, 1, 0, 3, 128, 127, },
        { 0, 1, 0, 3, 132, 68, },
-       { 2, 1, 0, 3, 132, 38, },
+       { 2, 1, 0, 3, 132, 36, },
        { 1, 1, 0, 3, 132, 70, },
        { 3, 1, 0, 3, 132, 68, },
-       { 4, 1, 0, 3, 132, 64, },
-       { 5, 1, 0, 3, 132, 38, },
+       { 4, 1, 0, 3, 132, 66, },
+       { 5, 1, 0, 3, 132, 36, },
        { 6, 1, 0, 3, 132, 68, },
        { 7, 1, 0, 3, 132, 30, },
        { 8, 1, 0, 3, 132, 68, },
        { 9, 1, 0, 3, 132, 127, },
        { 0, 1, 0, 3, 136, 68, },
-       { 2, 1, 0, 3, 136, 38, },
+       { 2, 1, 0, 3, 136, 36, },
        { 1, 1, 0, 3, 136, 70, },
        { 3, 1, 0, 3, 136, 68, },
-       { 4, 1, 0, 3, 136, 64, },
-       { 5, 1, 0, 3, 136, 38, },
+       { 4, 1, 0, 3, 136, 66, },
+       { 5, 1, 0, 3, 136, 36, },
        { 6, 1, 0, 3, 136, 68, },
        { 7, 1, 0, 3, 136, 30, },
        { 8, 1, 0, 3, 136, 68, },
        { 9, 1, 0, 3, 136, 127, },
-       { 0, 1, 0, 3, 140, 60, },
-       { 2, 1, 0, 3, 140, 38, },
+       { 0, 1, 0, 3, 140, 58, },
+       { 2, 1, 0, 3, 140, 36, },
        { 1, 1, 0, 3, 140, 70, },
-       { 3, 1, 0, 3, 140, 60, },
-       { 4, 1, 0, 3, 140, 64, },
-       { 5, 1, 0, 3, 140, 38, },
+       { 3, 1, 0, 3, 140, 58, },
+       { 4, 1, 0, 3, 140, 66, },
+       { 5, 1, 0, 3, 140, 36, },
        { 6, 1, 0, 3, 140, 60, },
        { 7, 1, 0, 3, 140, 30, },
        { 8, 1, 0, 3, 140, 60, },
        { 9, 1, 0, 3, 140, 127, },
        { 0, 1, 0, 3, 144, 68, },
        { 2, 1, 0, 3, 144, 127, },
-       { 1, 1, 0, 3, 144, 127, },
+       { 1, 1, 0, 3, 144, 70, },
        { 3, 1, 0, 3, 144, 68, },
-       { 4, 1, 0, 3, 144, 64, },
+       { 4, 1, 0, 3, 144, 66, },
        { 5, 1, 0, 3, 144, 127, },
        { 6, 1, 0, 3, 144, 68, },
        { 7, 1, 0, 3, 144, 127, },
        { 8, 1, 0, 3, 144, 68, },
        { 9, 1, 0, 3, 144, 127, },
        { 0, 1, 0, 3, 149, 76, },
-       { 2, 1, 0, 3, 149, -128, },
+       { 2, 1, 0, 3, 149, 4, },
        { 1, 1, 0, 3, 149, 127, },
        { 3, 1, 0, 3, 149, 76, },
-       { 4, 1, 0, 3, 149, 60, },
+       { 4, 1, 0, 3, 149, 62, },
        { 5, 1, 0, 3, 149, 76, },
        { 6, 1, 0, 3, 149, 76, },
        { 7, 1, 0, 3, 149, 30, },
        { 8, 1, 0, 3, 149, 72, },
-       { 9, 1, 0, 3, 149, -128, },
+       { 9, 1, 0, 3, 149, 4, },
        { 0, 1, 0, 3, 153, 76, },
-       { 2, 1, 0, 3, 153, -128, },
+       { 2, 1, 0, 3, 153, 4, },
        { 1, 1, 0, 3, 153, 127, },
        { 3, 1, 0, 3, 153, 76, },
-       { 4, 1, 0, 3, 153, 60, },
+       { 4, 1, 0, 3, 153, 62, },
        { 5, 1, 0, 3, 153, 76, },
        { 6, 1, 0, 3, 153, 76, },
        { 7, 1, 0, 3, 153, 30, },
        { 8, 1, 0, 3, 153, 76, },
-       { 9, 1, 0, 3, 153, -128, },
+       { 9, 1, 0, 3, 153, 4, },
        { 0, 1, 0, 3, 157, 76, },
-       { 2, 1, 0, 3, 157, -128, },
+       { 2, 1, 0, 3, 157, 4, },
        { 1, 1, 0, 3, 157, 127, },
        { 3, 1, 0, 3, 157, 76, },
-       { 4, 1, 0, 3, 157, 60, },
+       { 4, 1, 0, 3, 157, 62, },
        { 5, 1, 0, 3, 157, 76, },
        { 6, 1, 0, 3, 157, 76, },
        { 7, 1, 0, 3, 157, 30, },
        { 8, 1, 0, 3, 157, 76, },
-       { 9, 1, 0, 3, 157, -128, },
+       { 9, 1, 0, 3, 157, 4, },
        { 0, 1, 0, 3, 161, 76, },
-       { 2, 1, 0, 3, 161, -128, },
+       { 2, 1, 0, 3, 161, 4, },
        { 1, 1, 0, 3, 161, 127, },
        { 3, 1, 0, 3, 161, 76, },
-       { 4, 1, 0, 3, 161, 60, },
+       { 4, 1, 0, 3, 161, 62, },
        { 5, 1, 0, 3, 161, 76, },
        { 6, 1, 0, 3, 161, 76, },
        { 7, 1, 0, 3, 161, 30, },
        { 8, 1, 0, 3, 161, 76, },
-       { 9, 1, 0, 3, 161, -128, },
+       { 9, 1, 0, 3, 161, 4, },
        { 0, 1, 0, 3, 165, 76, },
-       { 2, 1, 0, 3, 165, -128, },
+       { 2, 1, 0, 3, 165, 4, },
        { 1, 1, 0, 3, 165, 127, },
        { 3, 1, 0, 3, 165, 76, },
-       { 4, 1, 0, 3, 165, 60, },
+       { 4, 1, 0, 3, 165, 62, },
        { 5, 1, 0, 3, 165, 76, },
        { 6, 1, 0, 3, 165, 76, },
        { 7, 1, 0, 3, 165, 30, },
        { 8, 1, 0, 3, 165, 76, },
-       { 9, 1, 0, 3, 165, -128, },
+       { 9, 1, 0, 3, 165, 4, },
        { 0, 1, 1, 2, 38, 66, },
        { 2, 1, 1, 2, 38, 64, },
-       { 1, 1, 1, 2, 38, 62, },
+       { 1, 1, 1, 2, 38, 64, },
        { 3, 1, 1, 2, 38, 64, },
-       { 4, 1, 1, 2, 38, 72, },
+       { 4, 1, 1, 2, 38, 64, },
        { 5, 1, 1, 2, 38, 64, },
        { 6, 1, 1, 2, 38, 64, },
        { 7, 1, 1, 2, 38, 54, },
@@ -43379,9 +43379,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 9, 1, 1, 2, 38, 64, },
        { 0, 1, 1, 2, 46, 72, },
        { 2, 1, 1, 2, 46, 64, },
-       { 1, 1, 1, 2, 46, 62, },
+       { 1, 1, 1, 2, 46, 64, },
        { 3, 1, 1, 2, 46, 64, },
-       { 4, 1, 1, 2, 46, 60, },
+       { 4, 1, 1, 2, 46, 70, },
        { 5, 1, 1, 2, 46, 64, },
        { 6, 1, 1, 2, 46, 64, },
        { 7, 1, 1, 2, 46, 54, },
@@ -43389,7 +43389,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 9, 1, 1, 2, 46, 64, },
        { 0, 1, 1, 2, 54, 72, },
        { 2, 1, 1, 2, 54, 64, },
-       { 1, 1, 1, 2, 54, 62, },
+       { 1, 1, 1, 2, 54, 64, },
        { 3, 1, 1, 2, 54, 64, },
        { 4, 1, 1, 2, 54, 72, },
        { 5, 1, 1, 2, 54, 64, },
@@ -43397,21 +43397,21 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 7, 1, 1, 2, 54, 54, },
        { 8, 1, 1, 2, 54, 72, },
        { 9, 1, 1, 2, 54, 64, },
-       { 0, 1, 1, 2, 62, 64, },
+       { 0, 1, 1, 2, 62, 60, },
        { 2, 1, 1, 2, 62, 64, },
        { 1, 1, 1, 2, 62, 62, },
-       { 3, 1, 1, 2, 62, 64, },
-       { 4, 1, 1, 2, 62, 70, },
+       { 3, 1, 1, 2, 62, 60, },
+       { 4, 1, 1, 2, 62, 60, },
        { 5, 1, 1, 2, 62, 64, },
        { 6, 1, 1, 2, 62, 64, },
        { 7, 1, 1, 2, 62, 54, },
        { 8, 1, 1, 2, 62, 64, },
        { 9, 1, 1, 2, 62, 64, },
-       { 0, 1, 1, 2, 102, 58, },
+       { 0, 1, 1, 2, 102, 60, },
        { 2, 1, 1, 2, 102, 64, },
        { 1, 1, 1, 2, 102, 72, },
-       { 3, 1, 1, 2, 102, 58, },
-       { 4, 1, 1, 2, 102, 72, },
+       { 3, 1, 1, 2, 102, 60, },
+       { 4, 1, 1, 2, 102, 64, },
        { 5, 1, 1, 2, 102, 64, },
        { 6, 1, 1, 2, 102, 58, },
        { 7, 1, 1, 2, 102, 54, },
@@ -43459,7 +43459,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 9, 1, 1, 2, 134, 127, },
        { 0, 1, 1, 2, 142, 72, },
        { 2, 1, 1, 2, 142, 127, },
-       { 1, 1, 1, 2, 142, 127, },
+       { 1, 1, 1, 2, 142, 72, },
        { 3, 1, 1, 2, 142, 72, },
        { 4, 1, 1, 2, 142, 72, },
        { 5, 1, 1, 2, 142, 127, },
@@ -43468,7 +43468,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 8, 1, 1, 2, 142, 72, },
        { 9, 1, 1, 2, 142, 127, },
        { 0, 1, 1, 2, 151, 72, },
-       { 2, 1, 1, 2, 151, -128, },
+       { 2, 1, 1, 2, 151, 28, },
        { 1, 1, 1, 2, 151, 127, },
        { 3, 1, 1, 2, 151, 72, },
        { 4, 1, 1, 2, 151, 72, },
@@ -43476,9 +43476,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 1, 2, 151, 72, },
        { 7, 1, 1, 2, 151, 54, },
        { 8, 1, 1, 2, 151, 72, },
-       { 9, 1, 1, 2, 151, -128, },
+       { 9, 1, 1, 2, 151, 28, },
        { 0, 1, 1, 2, 159, 72, },
-       { 2, 1, 1, 2, 159, -128, },
+       { 2, 1, 1, 2, 159, 28, },
        { 1, 1, 1, 2, 159, 127, },
        { 3, 1, 1, 2, 159, 72, },
        { 4, 1, 1, 2, 159, 72, },
@@ -43486,12 +43486,12 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 1, 2, 159, 72, },
        { 7, 1, 1, 2, 159, 54, },
        { 8, 1, 1, 2, 159, 72, },
-       { 9, 1, 1, 2, 159, -128, },
+       { 9, 1, 1, 2, 159, 28, },
        { 0, 1, 1, 3, 38, 60, },
        { 2, 1, 1, 3, 38, 40, },
        { 1, 1, 1, 3, 38, 50, },
        { 3, 1, 1, 3, 38, 40, },
-       { 4, 1, 1, 3, 38, 62, },
+       { 4, 1, 1, 3, 38, 54, },
        { 5, 1, 1, 3, 38, 40, },
        { 6, 1, 1, 3, 38, 52, },
        { 7, 1, 1, 3, 38, 30, },
@@ -43501,7 +43501,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 1, 1, 3, 46, 40, },
        { 1, 1, 1, 3, 46, 50, },
        { 3, 1, 1, 3, 46, 40, },
-       { 4, 1, 1, 3, 46, 46, },
+       { 4, 1, 1, 3, 46, 54, },
        { 5, 1, 1, 3, 46, 40, },
        { 6, 1, 1, 3, 46, 52, },
        { 7, 1, 1, 3, 46, 30, },
@@ -43511,7 +43511,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 1, 1, 3, 54, 40, },
        { 1, 1, 1, 3, 54, 50, },
        { 3, 1, 1, 3, 54, 40, },
-       { 4, 1, 1, 3, 54, 62, },
+       { 4, 1, 1, 3, 54, 66, },
        { 5, 1, 1, 3, 54, 40, },
        { 6, 1, 1, 3, 54, 68, },
        { 7, 1, 1, 3, 54, 30, },
@@ -43521,17 +43521,17 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 1, 1, 3, 62, 40, },
        { 1, 1, 1, 3, 62, 48, },
        { 3, 1, 1, 3, 62, 40, },
-       { 4, 1, 1, 3, 62, 58, },
+       { 4, 1, 1, 3, 62, 50, },
        { 5, 1, 1, 3, 62, 40, },
        { 6, 1, 1, 3, 62, 58, },
        { 7, 1, 1, 3, 62, 30, },
        { 8, 1, 1, 3, 62, 58, },
        { 9, 1, 1, 3, 62, 40, },
-       { 0, 1, 1, 3, 102, 54, },
+       { 0, 1, 1, 3, 102, 56, },
        { 2, 1, 1, 3, 102, 40, },
        { 1, 1, 1, 3, 102, 70, },
-       { 3, 1, 1, 3, 102, 54, },
-       { 4, 1, 1, 3, 102, 64, },
+       { 3, 1, 1, 3, 102, 56, },
+       { 4, 1, 1, 3, 102, 54, },
        { 5, 1, 1, 3, 102, 40, },
        { 6, 1, 1, 3, 102, 54, },
        { 7, 1, 1, 3, 102, 30, },
@@ -43541,7 +43541,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 1, 1, 3, 110, 40, },
        { 1, 1, 1, 3, 110, 70, },
        { 3, 1, 1, 3, 110, 68, },
-       { 4, 1, 1, 3, 110, 64, },
+       { 4, 1, 1, 3, 110, 66, },
        { 5, 1, 1, 3, 110, 40, },
        { 6, 1, 1, 3, 110, 68, },
        { 7, 1, 1, 3, 110, 30, },
@@ -43551,7 +43551,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 1, 1, 3, 118, 40, },
        { 1, 1, 1, 3, 118, 70, },
        { 3, 1, 1, 3, 118, 127, },
-       { 4, 1, 1, 3, 118, 64, },
+       { 4, 1, 1, 3, 118, 66, },
        { 5, 1, 1, 3, 118, 127, },
        { 6, 1, 1, 3, 118, 68, },
        { 7, 1, 1, 3, 118, 30, },
@@ -43561,7 +43561,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 1, 1, 3, 126, 40, },
        { 1, 1, 1, 3, 126, 70, },
        { 3, 1, 1, 3, 126, 127, },
-       { 4, 1, 1, 3, 126, 64, },
+       { 4, 1, 1, 3, 126, 66, },
        { 5, 1, 1, 3, 126, 127, },
        { 6, 1, 1, 3, 126, 68, },
        { 7, 1, 1, 3, 126, 30, },
@@ -43571,7 +43571,7 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 2, 1, 1, 3, 134, 40, },
        { 1, 1, 1, 3, 134, 70, },
        { 3, 1, 1, 3, 134, 68, },
-       { 4, 1, 1, 3, 134, 64, },
+       { 4, 1, 1, 3, 134, 66, },
        { 5, 1, 1, 3, 134, 40, },
        { 6, 1, 1, 3, 134, 68, },
        { 7, 1, 1, 3, 134, 30, },
@@ -43579,16 +43579,16 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 9, 1, 1, 3, 134, 127, },
        { 0, 1, 1, 3, 142, 68, },
        { 2, 1, 1, 3, 142, 127, },
-       { 1, 1, 1, 3, 142, 127, },
+       { 1, 1, 1, 3, 142, 70, },
        { 3, 1, 1, 3, 142, 68, },
-       { 4, 1, 1, 3, 142, 64, },
+       { 4, 1, 1, 3, 142, 66, },
        { 5, 1, 1, 3, 142, 127, },
        { 6, 1, 1, 3, 142, 68, },
        { 7, 1, 1, 3, 142, 127, },
        { 8, 1, 1, 3, 142, 68, },
        { 9, 1, 1, 3, 142, 127, },
        { 0, 1, 1, 3, 151, 72, },
-       { 2, 1, 1, 3, 151, -128, },
+       { 2, 1, 1, 3, 151, 4, },
        { 1, 1, 1, 3, 151, 127, },
        { 3, 1, 1, 3, 151, 72, },
        { 4, 1, 1, 3, 151, 66, },
@@ -43596,9 +43596,9 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 1, 3, 151, 72, },
        { 7, 1, 1, 3, 151, 30, },
        { 8, 1, 1, 3, 151, 68, },
-       { 9, 1, 1, 3, 151, -128, },
+       { 9, 1, 1, 3, 151, 4, },
        { 0, 1, 1, 3, 159, 72, },
-       { 2, 1, 1, 3, 159, -128, },
+       { 2, 1, 1, 3, 159, 4, },
        { 1, 1, 1, 3, 159, 127, },
        { 3, 1, 1, 3, 159, 72, },
        { 4, 1, 1, 3, 159, 66, },
@@ -43606,32 +43606,32 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 6, 1, 1, 3, 159, 72, },
        { 7, 1, 1, 3, 159, 30, },
        { 8, 1, 1, 3, 159, 72, },
-       { 9, 1, 1, 3, 159, -128, },
-       { 0, 1, 2, 4, 42, 64, },
+       { 9, 1, 1, 3, 159, 4, },
+       { 0, 1, 2, 4, 42, 68, },
        { 2, 1, 2, 4, 42, 64, },
        { 1, 1, 2, 4, 42, 64, },
        { 3, 1, 2, 4, 42, 64, },
-       { 4, 1, 2, 4, 42, 68, },
+       { 4, 1, 2, 4, 42, 60, },
        { 5, 1, 2, 4, 42, 64, },
        { 6, 1, 2, 4, 42, 64, },
        { 7, 1, 2, 4, 42, 54, },
        { 8, 1, 2, 4, 42, 62, },
        { 9, 1, 2, 4, 42, 64, },
-       { 0, 1, 2, 4, 58, 62, },
+       { 0, 1, 2, 4, 58, 60, },
        { 2, 1, 2, 4, 58, 64, },
        { 1, 1, 2, 4, 58, 64, },
-       { 3, 1, 2, 4, 58, 62, },
-       { 4, 1, 2, 4, 58, 64, },
+       { 3, 1, 2, 4, 58, 60, },
+       { 4, 1, 2, 4, 58, 56, },
        { 5, 1, 2, 4, 58, 64, },
        { 6, 1, 2, 4, 58, 62, },
        { 7, 1, 2, 4, 58, 54, },
        { 8, 1, 2, 4, 58, 62, },
        { 9, 1, 2, 4, 58, 64, },
-       { 0, 1, 2, 4, 106, 58, },
+       { 0, 1, 2, 4, 106, 60, },
        { 2, 1, 2, 4, 106, 64, },
        { 1, 1, 2, 4, 106, 72, },
-       { 3, 1, 2, 4, 106, 58, },
-       { 4, 1, 2, 4, 106, 66, },
+       { 3, 1, 2, 4, 106, 60, },
+       { 4, 1, 2, 4, 106, 58, },
        { 5, 1, 2, 4, 106, 64, },
        { 6, 1, 2, 4, 106, 58, },
        { 7, 1, 2, 4, 106, 54, },
@@ -43649,84 +43649,84 @@ static const struct rtw_txpwr_lmt_cfg_pair rtw8822c_txpwr_lmt_type5[] = {
        { 9, 1, 2, 4, 122, 127, },
        { 0, 1, 2, 4, 138, 72, },
        { 2, 1, 2, 4, 138, 127, },
-       { 1, 1, 2, 4, 138, 127, },
+       { 1, 1, 2, 4, 138, 72, },
        { 3, 1, 2, 4, 138, 72, },
-       { 4, 1, 2, 4, 138, 68, },
+       { 4, 1, 2, 4, 138, 70, },
        { 5, 1, 2, 4, 138, 127, },
        { 6, 1, 2, 4, 138, 72, },
        { 7, 1, 2, 4, 138, 127, },
        { 8, 1, 2, 4, 138, 72, },
        { 9, 1, 2, 4, 138, 127, },
        { 0, 1, 2, 4, 155, 72, },
-       { 2, 1, 2, 4, 155, -128, },
+       { 2, 1, 2, 4, 155, 28, },
        { 1, 1, 2, 4, 155, 127, },
        { 3, 1, 2, 4, 155, 72, },
-       { 4, 1, 2, 4, 155, 68, },
+       { 4, 1, 2, 4, 155, 62, },
        { 5, 1, 2, 4, 155, 72, },
        { 6, 1, 2, 4, 155, 72, },
        { 7, 1, 2, 4, 155, 54, },
        { 8, 1, 2, 4, 155, 68, },
-       { 9, 1, 2, 4, 155, -128, },
-       { 0, 1, 2, 5, 42, 54, },
+       { 9, 1, 2, 4, 155, 28, },
+       { 0, 1, 2, 5, 42, 56, },
        { 2, 1, 2, 5, 42, 40, },
        { 1, 1, 2, 5, 42, 50, },
        { 3, 1, 2, 5, 42, 40, },
-       { 4, 1, 2, 5, 42, 58, },
+       { 4, 1, 2, 5, 42, 50, },
        { 5, 1, 2, 5, 42, 40, },
        { 6, 1, 2, 5, 42, 52, },
        { 7, 1, 2, 5, 42, 30, },
        { 8, 1, 2, 5, 42, 50, },
        { 9, 1, 2, 5, 42, 40, },
-       { 0, 1, 2, 5, 58, 52, },
+       { 0, 1, 2, 5, 58, 54, },
        { 2, 1, 2, 5, 58, 40, },
        { 1, 1, 2, 5, 58, 50, },
        { 3, 1, 2, 5, 58, 40, },
-       { 4, 1, 2, 5, 58, 56, },
+       { 4, 1, 2, 5, 58, 46, },
        { 5, 1, 2, 5, 58, 40, },
        { 6, 1, 2, 5, 58, 52, },
        { 7, 1, 2, 5, 58, 30, },
        { 8, 1, 2, 5, 58, 52, },
        { 9, 1, 2, 5, 58, 40, },
-       { 0, 1, 2, 5, 106, 50, },
+       { 0, 1, 2, 5, 106, 48, },
        { 2, 1, 2, 5, 106, 40, },
        { 1, 1, 2, 5, 106, 72, },
-       { 3, 1, 2, 5, 106, 50, },
-       { 4, 1, 2, 5, 106, 56, },
+       { 3, 1, 2, 5, 106, 48, },
+       { 4, 1, 2, 5, 106, 50, },
        { 5, 1, 2, 5, 106, 40, },
        { 6, 1, 2, 5, 106, 50, },
        { 7, 1, 2, 5, 106, 30, },
        { 8, 1, 2, 5, 106, 50, },
        { 9, 1, 2, 5, 106, 127, },
-       { 0, 1, 2, 5, 122, 66, },
+       { 0, 1, 2, 5, 122, 70, },
        { 2, 1, 2, 5, 122, 40, },
        { 1, 1, 2, 5, 122, 72, },
        { 3, 1, 2, 5, 122, 127, },
-       { 4, 1, 2, 5, 122, 56, },
+       { 4, 1, 2, 5, 122, 62, },
        { 5, 1, 2, 5, 122, 127, },
        { 6, 1, 2, 5, 122, 66, },
        { 7, 1, 2, 5, 122, 30, },
        { 8, 1, 2, 5, 122, 66, },
        { 9, 1, 2, 5, 122, 127, },
-       { 0, 1, 2, 5, 138, 66, },
+       { 0, 1, 2, 5, 138, 70, },
        { 2, 1, 2, 5, 138, 127, },
-       { 1, 1, 2, 5, 138, 127, },
-       { 3, 1, 2, 5, 138, 66, },
-       { 4, 1, 2, 5, 138, 58, },
+       { 1, 1, 2, 5, 138, 72, },
+       { 3, 1, 2, 5, 138, 70, },
+       { 4, 1, 2, 5, 138, 62, },
        { 5, 1, 2, 5, 138, 127, },
        { 6, 1, 2, 5, 138, 66, },
        { 7, 1, 2, 5, 138, 127, },
        { 8, 1, 2, 5, 138, 66, },
        { 9, 1, 2, 5, 138, 127, },
-       { 0, 1, 2, 5, 155, 62, },
-       { 2, 1, 2, 5, 155, -128, },
+       { 0, 1, 2, 5, 155, 72, },
+       { 2, 1, 2, 5, 155, 4, },
        { 1, 1, 2, 5, 155, 127, },
-       { 3, 1, 2, 5, 155, 62, },
-       { 4, 1, 2, 5, 155, 58, },
+       { 3, 1, 2, 5, 155, 72, },
+       { 4, 1, 2, 5, 155, 52, },
        { 5, 1, 2, 5, 155, 72, },
        { 6, 1, 2, 5, 155, 62, },
        { 7, 1, 2, 5, 155, 30, },
        { 8, 1, 2, 5, 155, 62, },
-       { 9, 1, 2, 5, 155, -128, },
+       { 9, 1, 2, 5, 155, 4, },
 };
 
 RTW_DECL_TABLE_TXPWR_LMT(rtw8822c_txpwr_lmt_type5);
index fdaa5a7..a029049 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <linux/etherdevice.h>
 #include <linux/if.h>
-#include <linux/version.h>
 #include "rsi_debugfs.h"
 #include "rsi_mgmt.h"
 #include "rsi_common.h"
index 8db323a..09df6ea 100644 (file)
@@ -95,17 +95,14 @@ static int st_nci_spi_write(void *phy_id, struct sk_buff *skb)
         */
        if (!r) {
                skb_rx = alloc_skb(skb->len, GFP_KERNEL);
-               if (!skb_rx) {
-                       r = -ENOMEM;
-                       goto exit;
-               }
+               if (!skb_rx)
+                       return -ENOMEM;
 
                skb_put(skb_rx, skb->len);
                memcpy(skb_rx->data, buf, skb->len);
                ndlc_recv(phy->ndlc, skb_rx);
        }
 
-exit:
        return r;
 }
 
index bc0a27d..dbac3a1 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/phy.h>
 #include <linux/export.h>
 #include <linux/device.h>
+#include <linux/nvmem-consumer.h>
 
 /**
  * of_get_phy_mode - Get phy mode for given device_node
@@ -45,42 +46,59 @@ int of_get_phy_mode(struct device_node *np, phy_interface_t *interface)
 }
 EXPORT_SYMBOL_GPL(of_get_phy_mode);
 
-static const void *of_get_mac_addr(struct device_node *np, const char *name)
+static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr)
 {
        struct property *pp = of_find_property(np, name, NULL);
 
-       if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value))
-               return pp->value;
-       return NULL;
+       if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value)) {
+               memcpy(addr, pp->value, ETH_ALEN);
+               return 0;
+       }
+       return -ENODEV;
 }
 
-static const void *of_get_mac_addr_nvmem(struct device_node *np)
+static int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr)
 {
-       int ret;
-       const void *mac;
-       u8 nvmem_mac[ETH_ALEN];
        struct platform_device *pdev = of_find_device_by_node(np);
+       struct nvmem_cell *cell;
+       const void *mac;
+       size_t len;
+       int ret;
 
-       if (!pdev)
-               return ERR_PTR(-ENODEV);
-
-       ret = nvmem_get_mac_address(&pdev->dev, &nvmem_mac);
-       if (ret) {
+       /* Try lookup by device first, there might be a nvmem_cell_lookup
+        * associated with a given device.
+        */
+       if (pdev) {
+               ret = nvmem_get_mac_address(&pdev->dev, addr);
                put_device(&pdev->dev);
-               return ERR_PTR(ret);
+               return ret;
        }
 
-       mac = devm_kmemdup(&pdev->dev, nvmem_mac, ETH_ALEN, GFP_KERNEL);
-       put_device(&pdev->dev);
-       if (!mac)
-               return ERR_PTR(-ENOMEM);
+       cell = of_nvmem_cell_get(np, "mac-address");
+       if (IS_ERR(cell))
+               return PTR_ERR(cell);
 
-       return mac;
+       mac = nvmem_cell_read(cell, &len);
+       nvmem_cell_put(cell);
+
+       if (IS_ERR(mac))
+               return PTR_ERR(mac);
+
+       if (len != ETH_ALEN || !is_valid_ether_addr(mac)) {
+               kfree(mac);
+               return -EINVAL;
+       }
+
+       memcpy(addr, mac, ETH_ALEN);
+       kfree(mac);
+
+       return 0;
 }
 
 /**
  * of_get_mac_address()
  * @np:                Caller's Device Node
+ * @addr:      Pointer to a six-byte array for the result
  *
  * Search the device tree for the best MAC address to use.  'mac-address' is
  * checked first, because that is supposed to contain to "most recent" MAC
@@ -101,24 +119,27 @@ static const void *of_get_mac_addr_nvmem(struct device_node *np)
  * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
  * but is all zeros.
  *
- * Return: Will be a valid pointer on success and ERR_PTR in case of error.
+ * Return: 0 on success and errno in case of error.
 */
-const void *of_get_mac_address(struct device_node *np)
+int of_get_mac_address(struct device_node *np, u8 *addr)
 {
-       const void *addr;
+       int ret;
+
+       if (!np)
+               return -ENODEV;
 
-       addr = of_get_mac_addr(np, "mac-address");
-       if (addr)
-               return addr;
+       ret = of_get_mac_addr(np, "mac-address", addr);
+       if (!ret)
+               return 0;
 
-       addr = of_get_mac_addr(np, "local-mac-address");
-       if (addr)
-               return addr;
+       ret = of_get_mac_addr(np, "local-mac-address", addr);
+       if (!ret)
+               return 0;
 
-       addr = of_get_mac_addr(np, "address");
-       if (addr)
-               return addr;
+       ret = of_get_mac_addr(np, "address", addr);
+       if (!ret)
+               return 0;
 
-       return of_get_mac_addr_nvmem(np);
+       return of_get_mac_addr_nvmem(np, addr);
 }
 EXPORT_SYMBOL(of_get_mac_address);
index 5dea6e9..da7c2cd 100644 (file)
@@ -407,14 +407,10 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
 int cvm_oct_common_init(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
-       const u8 *mac = NULL;
+       int ret;
 
-       if (priv->of_node)
-               mac = of_get_mac_address(priv->of_node);
-
-       if (!IS_ERR_OR_NULL(mac))
-               ether_addr_copy(dev->dev_addr, mac);
-       else
+       ret = of_get_mac_address(priv->of_node, dev->dev_addr);
+       if (ret)
                eth_hw_addr_random(dev);
 
        /*
index e7bc198..4b9fdf9 100644 (file)
@@ -334,7 +334,6 @@ int wfx_probe(struct wfx_dev *wdev)
 {
        int i;
        int err;
-       const void *macaddr;
        struct gpio_desc *gpio_saved;
 
        // During first part of boot, gpio_wakeup cannot yet been used. So
@@ -423,9 +422,9 @@ int wfx_probe(struct wfx_dev *wdev)
 
        for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
                eth_zero_addr(wdev->addresses[i].addr);
-               macaddr = of_get_mac_address(wdev->dev->of_node);
-               if (!IS_ERR_OR_NULL(macaddr)) {
-                       ether_addr_copy(wdev->addresses[i].addr, macaddr);
+               err = of_get_mac_address(wdev->dev->of_node,
+                                        wdev->addresses[i].addr);
+               if (!err) {
                        wdev->addresses[i].addr[ETH_ALEN - 1] += i;
                } else {
                        ether_addr_copy(wdev->addresses[i].addr,
index 71bbfcf..daef3b0 100644 (file)
@@ -13,7 +13,7 @@
 
 struct net_device;
 extern int of_get_phy_mode(struct device_node *np, phy_interface_t *interface);
-extern const void *of_get_mac_address(struct device_node *np);
+extern int of_get_mac_address(struct device_node *np, u8 *mac);
 extern struct net_device *of_find_net_device_by_node(struct device_node *np);
 #else
 static inline int of_get_phy_mode(struct device_node *np,
@@ -22,9 +22,9 @@ static inline int of_get_phy_mode(struct device_node *np,
        return -ENODEV;
 }
 
-static inline const void *of_get_mac_address(struct device_node *np)
+static inline int of_get_mac_address(struct device_node *np, u8 *mac)
 {
-       return ERR_PTR(-ENODEV);
+       return -ENODEV;
 }
 
 static inline struct net_device *of_find_net_device_by_node(struct device_node *np)
index e338ef7..97edb31 100644 (file)
@@ -238,6 +238,8 @@ struct plat_stmmacenet_data {
        struct pci_dev *pdev;
        bool has_crossts;
        int int_snapshot_num;
+       int ext_snapshot_num;
+       bool ext_snapshot_en;
        bool multi_msi_en;
        int msi_mac_vec;
        int msi_wol_vec;
index 57b2c49..1259b0f 100644 (file)
@@ -260,7 +260,7 @@ struct dsa_port {
        unsigned int            index;
        const char              *name;
        struct dsa_port         *cpu_dp;
-       const char              *mac;
+       u8                      mac[ETH_ALEN];
        struct device_node      *dn;
        unsigned int            ageing_time;
        bool                    vlan_filtering;
index 3ad9e84..14010c0 100644 (file)
@@ -3773,13 +3773,13 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
        unsigned int tnl_hlen = skb_tnl_header_len(skb);
        unsigned int delta_truesize = 0;
        unsigned int delta_len = 0;
+       struct sk_buff *tail = NULL;
        struct sk_buff *nskb, *tmp;
        int err;
 
        skb_push(skb, -skb_network_offset(skb) + offset);
 
        skb_shinfo(skb)->frag_list = NULL;
-       skb->next = list_skb;
 
        do {
                nskb = list_skb;
@@ -3797,8 +3797,17 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
                        }
                }
 
-               if (unlikely(err))
+               if (!tail)
+                       skb->next = nskb;
+               else
+                       tail->next = nskb;
+
+               if (unlikely(err)) {
+                       nskb->next = list_skb;
                        goto err_linearize;
+               }
+
+               tail = nskb;
 
                delta_len += nskb->len;
                delta_truesize += nskb->truesize;
@@ -3825,7 +3834,7 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
 
        skb_gso_reset(skb);
 
-       skb->prev = nskb;
+       skb->prev = tail;
 
        if (skb_needs_linearize(skb, features) &&
            __skb_linearize(skb))
index 3c3e56a..d7c22e3 100644 (file)
@@ -392,7 +392,7 @@ static int dsa_port_setup(struct dsa_port *dp)
 
                break;
        case DSA_PORT_TYPE_USER:
-               dp->mac = of_get_mac_address(dp->dn);
+               of_get_mac_address(dp->dn, dp->mac);
                err = dsa_slave_create(dp);
                if (err)
                        break;
index 995e0e1..9300cb6 100644 (file)
@@ -1896,7 +1896,7 @@ int dsa_slave_create(struct dsa_port *port)
        slave_dev->hw_features |= NETIF_F_HW_TC;
        slave_dev->features |= NETIF_F_LLTX;
        slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
-       if (!IS_ERR_OR_NULL(port->mac))
+       if (!is_zero_ether_addr(port->mac))
                ether_addr_copy(slave_dev->dev_addr, port->mac);
        else
                eth_hw_addr_inherit(slave_dev, master);
index 933b427..9cce612 100644 (file)
@@ -511,13 +511,14 @@ unsigned char * __weak arch_get_platform_mac_address(void)
 
 int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr)
 {
-       const unsigned char *addr = NULL;
+       unsigned char *addr;
+       int ret;
 
-       if (dev->of_node)
-               addr = of_get_mac_address(dev->of_node);
-       if (IS_ERR_OR_NULL(addr))
-               addr = arch_get_platform_mac_address();
+       ret = of_get_mac_address(dev->of_node, mac_addr);
+       if (!ret)
+               return 0;
 
+       addr = arch_get_platform_mac_address();
        if (!addr)
                return -ENODEV;
 
index dd1c752..35803ab 100644 (file)
@@ -754,7 +754,7 @@ int esp_input_done2(struct sk_buff *skb, int err)
        int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
        int ihl;
 
-       if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
+       if (!xo || !(xo->flags & CRYPTO_DONE))
                kfree(ESP_SKB_CB(skb)->tmp);
 
        if (unlikely(err))
index 76990e1..8bd988f 100644 (file)
@@ -1196,6 +1196,11 @@ int icmp_rcv(struct sk_buff *skb)
                goto success_check;
        }
 
+       if (icmph->type == ICMP_EXT_ECHOREPLY) {
+               success = ping_rcv(skb);
+               goto success_check;
+       }
+
        /*
         *      18 is the highest 'known' ICMP type. Anything else is a mystery
         *
index 080ee7f..20d492d 100644 (file)
@@ -705,7 +705,7 @@ static int ah6_init_state(struct xfrm_state *x)
 
        if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
            crypto_ahash_digestsize(ahash)) {
-               pr_info("AH: %s digestsize %u != %hu\n",
+               pr_info("AH: %s digestsize %u != %u\n",
                        x->aalg->alg_name, crypto_ahash_digestsize(ahash),
                        aalg_desc->uinfo.auth.icv_fullbits/8);
                goto error;
index 727d791..393ae2b 100644 (file)
@@ -1147,7 +1147,7 @@ static int esp_init_authenc(struct xfrm_state *x)
                err = -EINVAL;
                if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
                    crypto_aead_authsize(aead)) {
-                       pr_info("ESP: %s digestsize %u != %hu\n",
+                       pr_info("ESP: %s digestsize %u != %u\n",
                                x->aalg->alg_name,
                                crypto_aead_authsize(aead),
                                aalg_desc->uinfo.auth.icv_fullbits / 8);
index 4af56af..40ed4fc 100644 (file)
@@ -318,7 +318,7 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb,  netdev_features
        esp.plen = esp.clen - skb->len - esp.tfclen;
        esp.tailen = esp.tfclen + esp.plen + alen;
 
-       if (!hw_offload || (hw_offload && !skb_is_gso(skb))) {
+       if (!hw_offload || !skb_is_gso(skb)) {
                esp.nfrags = esp6_output_head(x, skb, &esp);
                if (esp.nfrags < 0)
                        return esp.nfrags;
index 1bca2b0..e8398ff 100644 (file)
@@ -916,6 +916,10 @@ static int icmpv6_rcv(struct sk_buff *skb)
                success = ping_rcv(skb);
                break;
 
+       case ICMPV6_EXT_ECHO_REPLY:
+               success = ping_rcv(skb);
+               break;
+
        case ICMPV6_PKT_TOOBIG:
                /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
                   standard destination cache. Seems, only "advanced"