aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/net/dsa/qca8k.txt40
-rw-r--r--Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml5
-rw-r--r--Documentation/devicetree/bindings/net/rockchip-dwmac.yaml30
-rw-r--r--Documentation/networking/ip-sysctl.rst58
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3308.dtsi22
-rw-r--r--drivers/atm/iphase.c13
-rw-r--r--drivers/atm/iphase.h1
-rw-r--r--drivers/atm/nicstar.c2
-rw-r--r--drivers/isdn/hardware/mISDN/hfcpci.c2
-rw-r--r--drivers/net/dsa/qca8k.c762
-rw-r--r--drivers/net/dsa/qca8k.h58
-rw-r--r--drivers/net/ethernet/3com/3c59x.c2
-rw-r--r--drivers/net/ethernet/8390/axnet_cs.c14
-rw-r--r--drivers/net/ethernet/8390/pcnet_cs.c2
-rw-r--r--drivers/net/ethernet/8390/smc-ultra.c6
-rw-r--r--drivers/net/ethernet/8390/stnic.c2
-rw-r--r--drivers/net/ethernet/alteon/acenic.c26
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c4
-rw-r--r--drivers/net/ethernet/amd/amd8111e.h6
-rw-r--r--drivers/net/ethernet/amd/atarilance.c2
-rw-r--r--drivers/net/ethernet/amd/declance.c2
-rw-r--r--drivers/net/ethernet/amd/lance.c4
-rw-r--r--drivers/net/ethernet/amd/ni65.c12
-rw-r--r--drivers/net/ethernet/amd/nmclan_cs.c12
-rw-r--r--drivers/net/ethernet/amd/sun3lance.c12
-rw-r--r--drivers/net/ethernet/apple/bmac.c30
-rw-r--r--drivers/net/ethernet/apple/mace.c8
-rw-r--r--drivers/net/ethernet/arc/emac_rockchip.c2
-rw-r--r--drivers/net/ethernet/atheros/alx/alx.h2
-rw-r--r--drivers/net/ethernet/atheros/alx/ethtool.c21
-rw-r--r--drivers/net/ethernet/atheros/alx/main.c84
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c.h3
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_hw.c35
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_hw.h8
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c61
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c4
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c2
-rw-r--r--drivers/net/ethernet/broadcom/b44.c20
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c4
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.c2
-rw-r--r--drivers/net/ethernet/cadence/macb_pci.c2
-rw-r--r--drivers/net/ethernet/cadence/macb_ptp.c2
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c8
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.c3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c2
-rw-r--r--drivers/net/ethernet/dec/tulip/de2104x.c4
-rw-r--r--drivers/net/ethernet/dec/tulip/de4x5.c6
-rw-r--r--drivers/net/ethernet/dec/tulip/dmfe.c18
-rw-r--r--drivers/net/ethernet/dec/tulip/pnic2.c4
-rw-r--r--drivers/net/ethernet/dec/tulip/uli526x.c10
-rw-r--r--drivers/net/ethernet/dec/tulip/winbond-840.c4
-rw-r--r--drivers/net/ethernet/dlink/sundance.c12
-rw-r--r--drivers/net/ethernet/fealnx.c2
-rw-r--r--drivers/net/ethernet/fujitsu/fmvj18x_cs.c6
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c9
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c16
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c76
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c8
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c4
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_enet.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ethtool.c6
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.h28
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c772
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h60
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c391
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.h27
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c4
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h11
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c544
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h15
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c34
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h7
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c17
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h1
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_ethtool.c1
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c18
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c6
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_if.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_io.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c2
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c1
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_main.c5
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_port.c10
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_rx.c1
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_tx.c4
-rw-r--r--drivers/net/ethernet/ibm/emac/emac.h2
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c3
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.c4
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c9
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c66
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c3
-rw-r--r--drivers/net/ethernet/marvell/skge.h2
-rw-r--r--drivers/net/ethernet/marvell/sky2.c30
-rw-r--r--drivers/net/ethernet/marvell/sky2.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Kconfig22
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Makefile4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/ib.h9
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/minimal.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.h3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h84
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c248
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/switchib.c595
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/switchx2.c1691
-rw-r--r--drivers/net/ethernet/micrel/ksz884x.c6
-rw-r--r--drivers/net/ethernet/microchip/encx24j600.c2
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c3
-rw-r--r--drivers/net/ethernet/natsemi/natsemi.c6
-rw-r--r--drivers/net/ethernet/neterion/s2io.c4
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-config.c2
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.c4
-rw-r--r--drivers/net/ethernet/netronome/nfp/ccm_mbox.c2
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c2
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h2
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c2
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c102
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_iscsi.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c2
-rw-r--r--drivers/net/ethernet/qualcomm/qca_debug.c1
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c10
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.h1
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c6
-rw-r--r--drivers/net/ethernet/realtek/8139too.c6
-rw-r--r--drivers/net/ethernet/realtek/atp.c4
-rw-r--r--drivers/net/ethernet/realtek/r8169_main.c8
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c4
-rw-r--r--drivers/net/ethernet/seeq/ether3.c10
-rw-r--r--drivers/net/ethernet/sfc/efx.c13
-rw-r--r--drivers/net/ethernet/sis/sis900.c22
-rw-r--r--drivers/net/ethernet/smsc/smc9194.c42
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c14
-rw-r--r--drivers/net/ethernet/socionext/sni_ave.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c207
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c2
-rw-r--r--drivers/net/ethernet/sun/cassini.c2
-rw-r--r--drivers/net/ethernet/sun/sungem.c20
-rw-r--r--drivers/net/ethernet/sun/sunhme.c6
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c2
-rw-r--r--drivers/net/ethernet/via/via-velocity.c6
-rw-r--r--drivers/net/ethernet/xircom/xirc2ps_cs.c2
-rw-r--r--drivers/net/mdio/mdio-ipq8064.c70
-rw-r--r--drivers/net/pcs/pcs-xpcs.c51
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/adin.c2
-rw-r--r--drivers/net/phy/at803x.c162
-rw-r--r--drivers/net/phy/nxp-c45-tja11xx.c531
-rw-r--r--drivers/net/phy/rockchip.c2
-rw-r--r--drivers/net/tun.c16
-rw-r--r--drivers/net/usb/Kconfig10
-rw-r--r--drivers/net/usb/cdc_mbim.c1
-rw-r--r--drivers/net/usb/huawei_cdc_ncm.c1
-rw-r--r--drivers/net/usb/qmi_wwan.c3
-rw-r--r--drivers/net/virtio_net.c20
-rw-r--r--drivers/net/wan/Kconfig4
-rw-r--r--drivers/net/wan/c101.c39
-rw-r--r--drivers/net/wan/fsl_ucc_hdlc.c3
-rw-r--r--drivers/net/wwan/wwan_core.c34
-rw-r--r--drivers/nfc/s3fwrn5/i2c.c30
-rw-r--r--drivers/ptp/ptp_clock.c21
-rw-r--r--drivers/usb/class/cdc-wdm.c180
-rw-r--r--drivers/vhost/net.c6
-rw-r--r--include/linux/if_bridge.h8
-rw-r--r--include/linux/of_mdio.h7
-rw-r--r--include/linux/pcs/pcs-xpcs.h2
-rw-r--r--include/linux/ptp_clock_kernel.h34
-rw-r--r--include/linux/stmmac.h1
-rw-r--r--include/linux/usb/cdc-wdm.h3
-rw-r--r--include/linux/wwan.h4
-rw-r--r--include/net/ip_fib.h43
-rw-r--r--include/net/ipv6.h8
-rw-r--r--include/net/netns/ipv4.h1
-rw-r--r--include/net/netns/ipv6.h3
-rw-r--r--include/net/protocol.h1
-rw-r--r--include/trace/events/tcp.h76
-rw-r--r--include/uapi/linux/if_bridge.h2
-rw-r--r--net/bridge/br_forward.c5
-rw-r--r--net/bridge/br_input.c2
-rw-r--r--net/bridge/br_mdb.c57
-rw-r--r--net/bridge/br_multicast.c445
-rw-r--r--net/bridge/br_private.h70
-rw-r--r--net/caif/chnl_net.c2
-rw-r--r--net/core/bpf_sk_storage.c3
-rw-r--r--net/core/dev.c11
-rw-r--r--net/core/neighbour.c2
-rw-r--r--net/core/net-traces.c1
-rw-r--r--net/core/rtnetlink.c26
-rw-r--r--net/dcb/dcbnl.c2
-rw-r--r--net/dccp/ipv4.c1
-rw-r--r--net/ipv4/af_inet.c4
-rw-r--r--net/ipv4/cipso_ipv4.c3
-rw-r--r--net/ipv4/devinet.c4
-rw-r--r--net/ipv4/fib_frontend.c10
-rw-r--r--net/ipv4/gre_demux.c1
-rw-r--r--net/ipv4/ipmr.c1
-rw-r--r--net/ipv4/protocol.c6
-rw-r--r--net/ipv4/route.c127
-rw-r--r--net/ipv4/sysctl_net_ipv4.c31
-rw-r--r--net/ipv4/tcp_input.c1
-rw-r--r--net/ipv4/tcp_ipv4.c3
-rw-r--r--net/ipv4/tunnel4.c3
-rw-r--r--net/ipv4/udplite.c1
-rw-r--r--net/ipv4/xfrm4_protocol.c3
-rw-r--r--net/ipv6/ip6_fib.c9
-rw-r--r--net/ipv6/route.c131
-rw-r--r--net/ipv6/sysctl_net_ipv6.c31
-rw-r--r--net/ipv6/tcp_ipv6.c2
-rw-r--r--net/l2tp/l2tp_ip.c1
-rw-r--r--net/netlabel/netlabel_calipso.c4
-rw-r--r--net/netlabel/netlabel_cipso_v4.c4
-rw-r--r--net/netlabel/netlabel_mgmt.c8
-rw-r--r--net/netlabel/netlabel_unlabeled.c10
-rw-r--r--net/netlabel/netlabel_user.h4
-rw-r--r--net/openvswitch/conntrack.c11
-rw-r--r--net/packet/af_packet.c7
-rw-r--r--net/sched/sch_taprio.c88
-rw-r--r--net/sctp/protocol.c1
-rw-r--r--net/tls/tls_sw.c3
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/port_scale.sh4
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/qos_headroom.sh69
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh14
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/qos_pfc.sh24
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/tc_sample.sh12
-rwxr-xr-xtools/testing/selftests/net/forwarding/custom_multipath_hash.sh364
-rwxr-xr-xtools/testing/selftests/net/forwarding/gre_custom_multipath_hash.sh456
-rwxr-xr-xtools/testing/selftests/net/forwarding/ip6gre_custom_multipath_hash.sh458
-rwxr-xr-xtools/testing/selftests/net/unicast_extensions.sh17
253 files changed, 6815 insertions, 4106 deletions
diff --git a/Documentation/devicetree/bindings/net/dsa/qca8k.txt b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
index ccbc6d89325d..8c73f67c43ca 100644
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
@@ -3,6 +3,7 @@
Required properties:
- compatible: should be one of:
+ "qca,qca8327"
"qca,qca8334"
"qca,qca8337"
@@ -20,6 +21,10 @@ described in dsa/dsa.txt. If the QCA8K switch is connect to a SoC's external
mdio-bus each subnode describing a port needs to have a valid phandle
referencing the internal PHY it is connected to. This is because there's no
N:N mapping of port and PHY id.
+To declare the internal mdio-bus configuration, declare a mdio node in the
+switch node and declare the phandle for the port referencing the internal
+PHY is connected to. In this config a internal mdio-bus is registered and
+the mdio MASTER is used as communication.
Don't use mixed external and internal mdio-bus configurations, as this is
not supported by the hardware.
@@ -149,26 +154,61 @@ for the internal master mdio-bus configuration:
port@1 {
reg = <1>;
label = "lan1";
+ phy-mode = "internal";
+ phy-handle = <&phy_port1>;
};
port@2 {
reg = <2>;
label = "lan2";
+ phy-mode = "internal";
+ phy-handle = <&phy_port2>;
};
port@3 {
reg = <3>;
label = "lan3";
+ phy-mode = "internal";
+ phy-handle = <&phy_port3>;
};
port@4 {
reg = <4>;
label = "lan4";
+ phy-mode = "internal";
+ phy-handle = <&phy_port4>;
};
port@5 {
reg = <5>;
label = "wan";
+ phy-mode = "internal";
+ phy-handle = <&phy_port5>;
+ };
+ };
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy_port1: phy@0 {
+ reg = <0>;
+ };
+
+ phy_port2: phy@1 {
+ reg = <1>;
+ };
+
+ phy_port3: phy@2 {
+ reg = <2>;
+ };
+
+ phy_port4: phy@3 {
+ reg = <3>;
+ };
+
+ phy_port5: phy@4 {
+ reg = <4>;
};
};
};
diff --git a/Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml b/Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml
index 477066e2b821..081742c2b726 100644
--- a/Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml
+++ b/Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml
@@ -27,6 +27,9 @@ properties:
reg:
maxItems: 1
+ clocks:
+ maxItems: 1
+
wake-gpios:
maxItems: 1
description:
@@ -80,6 +83,8 @@ examples:
en-gpios = <&gpf1 4 GPIO_ACTIVE_HIGH>;
wake-gpios = <&gpj0 2 GPIO_ACTIVE_HIGH>;
+
+ clocks = <&rpmcc 20>;
};
};
# UART example on Raspberry Pi
diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
index 5acddb6171bf..083623c8d718 100644
--- a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
@@ -19,10 +19,12 @@ select:
- rockchip,rk3128-gmac
- rockchip,rk3228-gmac
- rockchip,rk3288-gmac
+ - rockchip,rk3308-gmac
- rockchip,rk3328-gmac
- rockchip,rk3366-gmac
- rockchip,rk3368-gmac
- rockchip,rk3399-gmac
+ - rockchip,rk3568-gmac
- rockchip,rv1108-gmac
required:
- compatible
@@ -32,17 +34,23 @@ allOf:
properties:
compatible:
- items:
- - enum:
- - rockchip,px30-gmac
- - rockchip,rk3128-gmac
- - rockchip,rk3228-gmac
- - rockchip,rk3288-gmac
- - rockchip,rk3328-gmac
- - rockchip,rk3366-gmac
- - rockchip,rk3368-gmac
- - rockchip,rk3399-gmac
- - rockchip,rv1108-gmac
+ oneOf:
+ - items:
+ - enum:
+ - rockchip,px30-gmac
+ - rockchip,rk3128-gmac
+ - rockchip,rk3228-gmac
+ - rockchip,rk3288-gmac
+ - rockchip,rk3308-gmac
+ - rockchip,rk3328-gmac
+ - rockchip,rk3366-gmac
+ - rockchip,rk3368-gmac
+ - rockchip,rk3399-gmac
+ - rockchip,rv1108-gmac
+ - items:
+ - enum:
+ - rockchip,rk3568-gmac
+ - const: snps,dwmac-4.20a
clocks:
minItems: 5
diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
index c2ecc9894fd0..a5c250044500 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -99,6 +99,35 @@ fib_multipath_hash_policy - INTEGER
- 0 - Layer 3
- 1 - Layer 4
- 2 - Layer 3 or inner Layer 3 if present
+ - 3 - Custom multipath hash. Fields used for multipath hash calculation
+ are determined by fib_multipath_hash_fields sysctl
+
+fib_multipath_hash_fields - UNSIGNED INTEGER
+ When fib_multipath_hash_policy is set to 3 (custom multipath hash), the
+ fields used for multipath hash calculation are determined by this
+ sysctl.
+
+ This value is a bitmask which enables various fields for multipath hash
+ calculation.
+
+ Possible fields are:
+
+ ====== ============================
+ 0x0001 Source IP address
+ 0x0002 Destination IP address
+ 0x0004 IP protocol
+ 0x0008 Unused (Flow Label)
+ 0x0010 Source port
+ 0x0020 Destination port
+ 0x0040 Inner source IP address
+ 0x0080 Inner destination IP address
+ 0x0100 Inner IP protocol
+ 0x0200 Inner Flow Label
+ 0x0400 Inner source port
+ 0x0800 Inner destination port
+ ====== ============================
+
+ Default: 0x0007 (source IP, destination IP and IP protocol)
fib_sync_mem - UNSIGNED INTEGER
Amount of dirty memory from fib entries that can be backlogged before
@@ -1743,6 +1772,35 @@ fib_multipath_hash_policy - INTEGER
- 0 - Layer 3 (source and destination addresses plus flow label)
- 1 - Layer 4 (standard 5-tuple)
- 2 - Layer 3 or inner Layer 3 if present
+ - 3 - Custom multipath hash. Fields used for multipath hash calculation
+ are determined by fib_multipath_hash_fields sysctl
+
+fib_multipath_hash_fields - UNSIGNED INTEGER
+ When fib_multipath_hash_policy is set to 3 (custom multipath hash), the
+ fields used for multipath hash calculation are determined by this
+ sysctl.
+
+ This value is a bitmask which enables various fields for multipath hash
+ calculation.
+
+ Possible fields are:
+
+ ====== ============================
+ 0x0001 Source IP address
+ 0x0002 Destination IP address
+ 0x0004 IP protocol
+ 0x0008 Flow Label
+ 0x0010 Source port
+ 0x0020 Destination port
+ 0x0040 Inner source IP address
+ 0x0080 Inner destination IP address
+ 0x0100 Inner IP protocol
+ 0x0200 Inner Flow Label
+ 0x0400 Inner source port
+ 0x0800 Inner destination port
+ ====== ============================
+
+ Default: 0x0007 (source IP, destination IP and IP protocol)
anycast_src_echo_reply - BOOLEAN
Controls the use of anycast addresses as source addresses for ICMPv6
diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
index 0c5fa9801e6f..b815ce73e5c6 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
@@ -637,6 +637,28 @@
status = "disabled";
};
+ gmac: ethernet@ff4e0000 {
+ compatible = "rockchip,rk3308-gmac";
+ reg = <0x0 0xff4e0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ clocks = <&cru SCLK_MAC>, <&cru SCLK_MAC_RX_TX>,
+ <&cru SCLK_MAC_RX_TX>, <&cru SCLK_MAC_REF>,
+ <&cru SCLK_MAC>, <&cru ACLK_MAC>,
+ <&cru PCLK_MAC>, <&cru SCLK_MAC_RMII>;
+ clock-names = "stmmaceth", "mac_clk_rx",
+ "mac_clk_tx", "clk_mac_ref",
+ "clk_mac_refout", "aclk_mac",
+ "pclk_mac", "clk_mac_speed";
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rmii_pins &mac_refclk_12ma>;
+ resets = <&cru SRST_MAC_A>;
+ reset-names = "stmmaceth";
+ rockchip,grf = <&grf>;
+ status = "disabled";
+ };
+
cru: clock-controller@ff500000 {
compatible = "rockchip,rk3308-cru";
reg = <0x0 0xff500000 0x0 0x1000>;
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 933e3ff2ee8d..bc8e8d9f176b 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -47,6 +47,7 @@
#include <linux/errno.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
+#include <linux/ctype.h>
#include <linux/sonet.h>
#include <linux/skbuff.h>
#include <linux/time.h>
@@ -996,10 +997,12 @@ static void xdump( u_char* cp, int length, char* prefix )
}
pBuf += sprintf( pBuf, " " );
for(col = 0;count + col < length && col < 16; col++){
- if (isprint((int)cp[count + col]))
- pBuf += sprintf( pBuf, "%c", cp[count + col] );
- else
- pBuf += sprintf( pBuf, "." );
+ u_char c = cp[count + col];
+
+ if (isascii(c) && isprint(c))
+ pBuf += sprintf(pBuf, "%c", c);
+ else
+ pBuf += sprintf(pBuf, ".");
}
printk("%s\n", prntBuf);
count += col;
@@ -3279,7 +3282,7 @@ static void __exit ia_module_exit(void)
{
pci_unregister_driver(&ia_driver);
- del_timer(&ia_timer);
+ del_timer_sync(&ia_timer);
}
module_init(ia_module_init);
diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h
index 2beacf2fc1ec..2f5f8875cbd1 100644
--- a/drivers/atm/iphase.h
+++ b/drivers/atm/iphase.h
@@ -124,7 +124,6 @@
#define IF_RXPKT(A)
#endif /* CONFIG_ATM_IA_DEBUG */
-#define isprint(a) ((a >=' ')&&(a <= '~'))
#define ATM_DESC(skb) (skb->protocol)
#define IA_SKB_STATE(skb) (skb->protocol)
#define IA_DLED 1
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 5c7e4df159b9..b015c3e14336 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -299,7 +299,7 @@ static void __exit nicstar_cleanup(void)
{
XPRINTK("nicstar: nicstar_cleanup() called.\n");
- del_timer(&ns_timer);
+ del_timer_sync(&ns_timer);
pci_unregister_driver(&nicstar_driver);
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 56bd2e9db6ed..e501cb03f211 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -2342,7 +2342,7 @@ static void __exit
HFC_cleanup(void)
{
if (timer_pending(&hfc_tl))
- del_timer(&hfc_tl);
+ del_timer_sync(&hfc_tl);
pci_unregister_driver(&hfc_driver);
}
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index cdaf9f85a2cb..1f1b7c4dda13 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -11,6 +11,7 @@
#include <linux/netdevice.h>
#include <net/dsa.h>
#include <linux/of_net.h>
+#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <linux/if_bridge.h>
#include <linux/mdio.h>
@@ -127,90 +128,125 @@ qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)
"failed to write qca8k 32bit register\n");
}
-static void
+static int
qca8k_set_page(struct mii_bus *bus, u16 page)
{
+ int ret;
+
if (page == qca8k_current_page)
- return;
+ return 0;
- if (bus->write(bus, 0x18, 0, page) < 0)
+ ret = bus->write(bus, 0x18, 0, page);
+ if (ret < 0) {
dev_err_ratelimited(&bus->dev,
"failed to set qca8k page\n");
+ return ret;
+ }
+
qca8k_current_page = page;
+ usleep_range(1000, 2000);
+ return 0;
}
static u32
qca8k_read(struct qca8k_priv *priv, u32 reg)
{
+ struct mii_bus *bus = priv->bus;
u16 r1, r2, page;
u32 val;
qca8k_split_addr(reg, &r1, &r2, &page);
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
- qca8k_set_page(priv->bus, page);
- val = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
+ val = qca8k_set_page(bus, page);
+ if (val < 0)
+ goto exit;
- mutex_unlock(&priv->bus->mdio_lock);
+ val = qca8k_mii_read32(bus, 0x10 | r2, r1);
+exit:
+ mutex_unlock(&bus->mdio_lock);
return val;
}
-static void
+static int
qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val)
{
+ struct mii_bus *bus = priv->bus;
u16 r1, r2, page;
+ int ret;
qca8k_split_addr(reg, &r1, &r2, &page);
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+ ret = qca8k_set_page(bus, page);
+ if (ret < 0)
+ goto exit;
- qca8k_set_page(priv->bus, page);
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
- mutex_unlock(&priv->bus->mdio_lock);
+exit:
+ mutex_unlock(&bus->mdio_lock);
+ return ret;
}
-static u32
-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 val)
+static int
+qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
{
+ struct mii_bus *bus = priv->bus;
u16 r1, r2, page;
- u32 ret;
+ u32 val;
+ int ret;
qca8k_split_addr(reg, &r1, &r2, &page);
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+ ret = qca8k_set_page(bus, page);
+ if (ret < 0)
+ goto exit;
+
+ val = qca8k_mii_read32(bus, 0x10 | r2, r1);
+ if (val < 0) {
+ ret = val;
+ goto exit;
+ }
- qca8k_set_page(priv->bus, page);
- ret = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
- ret &= ~mask;
- ret |= val;
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, ret);
+ val &= ~mask;
+ val |= write_val;
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
- mutex_unlock(&priv->bus->mdio_lock);
+exit:
+ mutex_unlock(&bus->mdio_lock);
return ret;
}
-static void
+static int
qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val)
{
- qca8k_rmw(priv, reg, 0, val);
+ return qca8k_rmw(priv, reg, 0, val);
}
-static void
+static int
qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val)
{
- qca8k_rmw(priv, reg, val, 0);
+ return qca8k_rmw(priv, reg, val, 0);
}
static int
qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
+ int ret;
+
+ ret = qca8k_read(priv, reg);
+ if (ret < 0)
+ return ret;
- *val = qca8k_read(priv, reg);
+ *val = ret;
return 0;
}
@@ -220,9 +256,7 @@ qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
- qca8k_write(priv, reg, val);
-
- return 0;
+ return qca8k_write(priv, reg, val);
}
static const struct regmap_range qca8k_readable_ranges[] = {
@@ -262,32 +296,36 @@ static struct regmap_config qca8k_regmap_config = {
static int
qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
{
- unsigned long timeout;
-
- timeout = jiffies + msecs_to_jiffies(20);
+ u32 val;
+ int ret;
- /* loop until the busy flag has cleared */
- do {
- u32 val = qca8k_read(priv, reg);
- int busy = val & mask;
+ ret = read_poll_timeout(qca8k_read, val, !(val & mask),
+ 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
+ priv, reg);
- if (!busy)
- break;
- cond_resched();
- } while (!time_after_eq(jiffies, timeout));
+ /* Check if qca8k_read has failed for a different reason
+ * before returning -ETIMEDOUT
+ */
+ if (ret < 0 && val < 0)
+ return val;
- return time_after_eq(jiffies, timeout);
+ return ret;
}
-static void
+static int
qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
{
- u32 reg[4];
+ u32 reg[4], val;
int i;
/* load the ARL table into an array */
- for (i = 0; i < 4; i++)
- reg[i] = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4));
+ for (i = 0; i < 4; i++) {
+ val = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4));
+ if (val < 0)
+ return val;
+
+ reg[i] = val;
+ }
/* vid - 83:72 */
fdb->vid = (reg[2] >> QCA8K_ATU_VID_S) & QCA8K_ATU_VID_M;
@@ -302,6 +340,8 @@ qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
fdb->mac[3] = (reg[0] >> QCA8K_ATU_ADDR3_S) & 0xff;
fdb->mac[4] = (reg[0] >> QCA8K_ATU_ADDR4_S) & 0xff;
fdb->mac[5] = reg[0] & 0xff;
+
+ return 0;
}
static void
@@ -334,6 +374,7 @@ static int
qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)
{
u32 reg;
+ int ret;
/* Set the command and FDB index */
reg = QCA8K_ATU_FUNC_BUSY;
@@ -344,15 +385,20 @@ qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)
}
/* Write the function register triggering the table access */
- qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
+ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
+ if (ret)
+ return ret;
/* wait for completion */
- if (qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY))
- return -1;
+ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
+ if (ret)
+ return ret;
/* Check for table full violation when adding an entry */
if (cmd == QCA8K_FDB_LOAD) {
reg = qca8k_read(priv, QCA8K_REG_ATU_FUNC);
+ if (reg < 0)
+ return reg;
if (reg & QCA8K_ATU_FUNC_FULL)
return -1;
}
@@ -367,10 +413,10 @@ qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
- if (ret >= 0)
- qca8k_fdb_read(priv, fdb);
+ if (ret < 0)
+ return ret;
- return ret;
+ return qca8k_fdb_read(priv, fdb);
}
static int
@@ -412,6 +458,7 @@ static int
qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
{
u32 reg;
+ int ret;
/* Set the command and VLAN index */
reg = QCA8K_VTU_FUNC1_BUSY;
@@ -419,15 +466,20 @@ qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
reg |= vid << QCA8K_VTU_FUNC1_VID_S;
/* Write the function register triggering the table access */
- qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
+ if (ret)
+ return ret;
/* wait for completion */
- if (qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY))
- return -ETIMEDOUT;
+ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY);
+ if (ret)
+ return ret;
/* Check for table full violation when adding an entry */
if (cmd == QCA8K_VLAN_LOAD) {
reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC1);
+ if (reg < 0)
+ return reg;
if (reg & QCA8K_VTU_FUNC1_FULL)
return -ENOMEM;
}
@@ -454,6 +506,10 @@ qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged)
goto out;
reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC0);
+ if (reg < 0) {
+ ret = reg;
+ goto out;
+ }
reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN;
reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port));
if (untagged)
@@ -463,7 +519,9 @@ qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged)
reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG <<
QCA8K_VTU_FUNC0_EG_MODE_S(port);
- qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
+ if (ret)
+ goto out;
ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
out:
@@ -485,6 +543,10 @@ qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
goto out;
reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC0);
+ if (reg < 0) {
+ ret = reg;
+ goto out;
+ }
reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port));
reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT <<
QCA8K_VTU_FUNC0_EG_MODE_S(port);
@@ -504,7 +566,9 @@ qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
if (del) {
ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid);
} else {
- qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
+ if (ret)
+ goto out;
ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
}
@@ -514,15 +578,29 @@ out:
return ret;
}
-static void
+static int
qca8k_mib_init(struct qca8k_priv *priv)
{
+ int ret;
+
mutex_lock(&priv->reg_mutex);
- qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
- qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
- qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
- qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
+ ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
+
+exit:
mutex_unlock(&priv->reg_mutex);
+ return ret;
}
static void
@@ -556,52 +634,107 @@ qca8k_port_to_phy(int port)
}
static int
-qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)
+qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask)
+{
+ u16 r1, r2, page;
+ u32 val;
+ int ret;
+
+ qca8k_split_addr(reg, &r1, &r2, &page);
+
+ ret = read_poll_timeout(qca8k_mii_read32, val, !(val & mask), 0,
+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
+ bus, 0x10 | r2, r1);
+
+ /* Check if qca8k_read has failed for a different reason
+ * before returnting -ETIMEDOUT
+ */
+ if (ret < 0 && val < 0)
+ return val;
+
+ return ret;
+}
+
+static int
+qca8k_mdio_write(struct mii_bus *salve_bus, int phy, int regnum, u16 data)
{
- u32 phy, val;
+ struct qca8k_priv *priv = salve_bus->priv;
+ struct mii_bus *bus = priv->bus;
+ u16 r1, r2, page;
+ u32 val;
+ int ret;
if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
return -EINVAL;
- /* callee is responsible for not passing bad ports,
- * but we still would like to make spills impossible.
- */
- phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN |
QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
QCA8K_MDIO_MASTER_REG_ADDR(regnum) |
QCA8K_MDIO_MASTER_DATA(data);
- qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
+
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+ ret = qca8k_set_page(bus, page);
+ if (ret)
+ goto exit;
+
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
+
+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
+ QCA8K_MDIO_MASTER_BUSY);
+
+exit:
+ /* even if the busy_wait timeouts try to clear the MASTER_EN */
+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0);
+
+ mutex_unlock(&bus->mdio_lock);
- return qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
- QCA8K_MDIO_MASTER_BUSY);
+ return ret;
}
static int
-qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum)
+qca8k_mdio_read(struct mii_bus *salve_bus, int phy, int regnum)
{
- u32 phy, val;
+ struct qca8k_priv *priv = salve_bus->priv;
+ struct mii_bus *bus = priv->bus;
+ u16 r1, r2, page;
+ u32 val;
+ int ret;
if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
return -EINVAL;
- /* callee is responsible for not passing bad ports,
- * but we still would like to make spills impossible.
- */
- phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN |
QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
QCA8K_MDIO_MASTER_REG_ADDR(regnum);
- qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
+
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+ ret = qca8k_set_page(bus, page);
+ if (ret)
+ goto exit;
+
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
+
+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
+ QCA8K_MDIO_MASTER_BUSY);
+ if (ret)
+ goto exit;
+
+ val = qca8k_mii_read32(bus, 0x10 | r2, r1);
- if (qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
- QCA8K_MDIO_MASTER_BUSY))
- return -ETIMEDOUT;
+exit:
+ /* even if the busy_wait timeouts try to clear the MASTER_EN */
+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0);
- val = (qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL) &
- QCA8K_MDIO_MASTER_DATA_MASK);
+ mutex_unlock(&bus->mdio_lock);
+
+ if (val >= 0)
+ val &= QCA8K_MDIO_MASTER_DATA_MASK;
return val;
}
@@ -611,7 +744,14 @@ qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data)
{
struct qca8k_priv *priv = ds->priv;
- return qca8k_mdio_write(priv, port, regnum, data);
+ /* Check if the legacy mapping should be used and the
+ * port is not correctly mapped to the right PHY in the
+ * devicetree
+ */
+ if (priv->legacy_phy_port_mapping)
+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
+
+ return qca8k_mdio_write(priv->bus, port, regnum, data);
}
static int
@@ -620,7 +760,14 @@ qca8k_phy_read(struct dsa_switch *ds, int port, int regnum)
struct qca8k_priv *priv = ds->priv;
int ret;
- ret = qca8k_mdio_read(priv, port, regnum);
+ /* Check if the legacy mapping should be used and the
+ * port is not correctly mapped to the right PHY in the
+ * devicetree
+ */
+ if (priv->legacy_phy_port_mapping)
+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
+
+ ret = qca8k_mdio_read(priv->bus, port, regnum);
if (ret < 0)
return 0xffff;
@@ -629,14 +776,44 @@ qca8k_phy_read(struct dsa_switch *ds, int port, int regnum)
}
static int
+qca8k_mdio_register(struct qca8k_priv *priv, struct device_node *mdio)
+{
+ struct dsa_switch *ds = priv->ds;
+ struct mii_bus *bus;
+
+ bus = devm_mdiobus_alloc(ds->dev);
+
+ if (!bus)
+ return -ENOMEM;
+
+ bus->priv = (void *)priv;
+ bus->name = "qca8k slave mii";
+ bus->read = qca8k_mdio_read;
+ bus->write = qca8k_mdio_write;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d",
+ ds->index);
+
+ bus->parent = ds->dev;
+ bus->phy_mask = ~ds->phys_mii_mask;
+
+ ds->slave_mii_bus = bus;
+
+ return devm_of_mdiobus_register(priv->dev, bus, mdio);
+}
+
+static int
qca8k_setup_mdio_bus(struct qca8k_priv *priv)
{
u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg;
- struct device_node *ports, *port;
+ struct device_node *ports, *port, *mdio;
+ phy_interface_t mode;
int err;
ports = of_get_child_by_name(priv->dev->of_node, "ports");
if (!ports)
+ ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports");
+
+ if (!ports)
return -EINVAL;
for_each_available_child_of_node(ports, port) {
@@ -650,7 +827,10 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
if (!dsa_is_user_port(priv->ds, reg))
continue;
- if (of_property_read_bool(port, "phy-handle"))
+ of_get_phy_mode(port, &mode);
+
+ if (of_property_read_bool(port, "phy-handle") &&
+ mode != PHY_INTERFACE_MODE_INTERNAL)
external_mdio_mask |= BIT(reg);
else
internal_mdio_mask |= BIT(reg);
@@ -683,13 +863,89 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
* a dt-overlay and driver reload changed the configuration
*/
- qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
- QCA8K_MDIO_MASTER_EN);
- return 0;
+ return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
+ QCA8K_MDIO_MASTER_EN);
}
+ /* Check if the devicetree declare the port:phy mapping */
+ mdio = of_get_child_by_name(priv->dev->of_node, "mdio");
+ if (of_device_is_available(mdio)) {
+ err = qca8k_mdio_register(priv, mdio);
+ if (err)
+ of_node_put(mdio);
+
+ return err;
+ }
+
+ /* If a mapping can't be found the legacy mapping is used,
+ * using the qca8k_port_to_phy function
+ */
+ priv->legacy_phy_port_mapping = true;
priv->ops.phy_read = qca8k_phy_read;
priv->ops.phy_write = qca8k_phy_write;
+
+ return 0;
+}
+
+static int
+qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
+{
+ struct device_node *port_dn;
+ phy_interface_t mode;
+ struct dsa_port *dp;
+ u32 val;
+
+ /* CPU port is already checked */
+ dp = dsa_to_port(priv->ds, 0);
+
+ port_dn = dp->dn;
+
+ /* Check if port 0 is set to the correct type */
+ of_get_phy_mode(port_dn, &mode);
+ if (mode != PHY_INTERFACE_MODE_RGMII_ID &&
+ mode != PHY_INTERFACE_MODE_RGMII_RXID &&
+ mode != PHY_INTERFACE_MODE_RGMII_TXID) {
+ return 0;
+ }
+
+ switch (mode) {
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val))
+ val = 2;
+ else
+ /* Switch regs accept value in ns, convert ps to ns */
+ val = val / 1000;
+
+ if (val > QCA8K_MAX_DELAY) {
+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
+ val = 3;
+ }
+
+ priv->rgmii_rx_delay = val;
+ /* Stop here if we need to check only for rx delay */
+ if (mode != PHY_INTERFACE_MODE_RGMII_ID)
+ break;
+
+ fallthrough;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val))
+ val = 1;
+ else
+ /* Switch regs accept value in ns, convert ps to ns */
+ val = val / 1000;
+
+ if (val > QCA8K_MAX_DELAY) {
+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
+ val = 3;
+ }
+
+ priv->rgmii_tx_delay = val;
+ break;
+ default:
+ return 0;
+ }
+
return 0;
}
@@ -698,10 +954,11 @@ qca8k_setup(struct dsa_switch *ds)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
int ret, i;
+ u32 mask;
/* Make sure that port 0 is the cpu port */
if (!dsa_is_cpu_port(ds, 0)) {
- pr_err("port 0 is not the CPU port\n");
+ dev_err(priv->dev, "port 0 is not the CPU port");
return -EINVAL;
}
@@ -711,76 +968,163 @@ qca8k_setup(struct dsa_switch *ds)
priv->regmap = devm_regmap_init(ds->dev, NULL, priv,
&qca8k_regmap_config);
if (IS_ERR(priv->regmap))
- pr_warn("regmap initialization failed");
+ dev_warn(priv->dev, "regmap initialization failed");
ret = qca8k_setup_mdio_bus(priv);
if (ret)
return ret;
+ ret = qca8k_setup_of_rgmii_delay(priv);
+ if (ret)
+ return ret;
+
/* Enable CPU Port */
- qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
+ ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
+ if (ret) {
+ dev_err(priv->dev, "failed enabling CPU port");
+ return ret;
+ }
/* Enable MIB counters */
- qca8k_mib_init(priv);
+ ret = qca8k_mib_init(priv);
+ if (ret)
+ dev_warn(priv->dev, "mib init failed");
/* Enable QCA header mode on the cpu port */
- qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
+ if (ret) {
+ dev_err(priv->dev, "failed enabling QCA header mode");
+ return ret;
+ }
/* Disable forwarding by default on all ports */
- for (i = 0; i < QCA8K_NUM_PORTS; i++)
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_MEMBER, 0);
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+ QCA8K_PORT_LOOKUP_MEMBER, 0);
+ if (ret)
+ return ret;
+ }
/* Disable MAC by default on all ports */
for (i = 1; i < QCA8K_NUM_PORTS; i++)
qca8k_port_set_status(priv, i, 0);
/* Forward all unknown frames to CPU port for Linux processing */
- qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
+ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
+ if (ret)
+ return ret;
/* Setup connection between CPU port & user ports */
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
/* CPU port gets connected to all user ports of the switch */
if (dsa_is_cpu_port(ds, i)) {
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
+ if (ret)
+ return ret;
}
/* Individual user ports get connected to CPU port only */
if (dsa_is_user_port(ds, i)) {
int shift = 16 * (i % 2);
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_MEMBER,
- BIT(QCA8K_CPU_PORT));
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+ QCA8K_PORT_LOOKUP_MEMBER,
+ BIT(QCA8K_CPU_PORT));
+ if (ret)
+ return ret;
/* Enable ARP Auto-learning by default */
- qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_LEARN);
+ ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+ QCA8K_PORT_LOOKUP_LEARN);
+ if (ret)
+ return ret;
/* For port based vlans to work we need to set the
* default egress vid
*/
- qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
- 0xfff << shift,
- QCA8K_PORT_VID_DEF << shift);
- qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i),
- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
+ 0xfff << shift,
+ QCA8K_PORT_VID_DEF << shift);
+ if (ret)
+ return ret;
+
+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i),
+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
+ if (ret)
+ return ret;
+ }
+ }
+
+ /* The port 5 of the qca8337 have some problem in flood condition. The
+ * original legacy driver had some specific buffer and priority settings
+ * for the different port suggested by the QCA switch team. Add this
+ * missing settings to improve switch stability under load condition.
+ * This problem is limited to qca8337 and other qca8k switch are not affected.
+ */
+ if (priv->switch_id == QCA8K_ID_QCA8337) {
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ switch (i) {
+ /* The 2 CPU port and port 5 requires some different
+ * priority than any other ports.
+ */
+ case 0:
+ case 5:
+ case 6:
+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) |
+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e);
+ break;
+ default:
+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) |
+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);
+ }
+ qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask);
+
+ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) |
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_WRED_EN;
+ qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i),
+ QCA8K_PORT_HOL_CTRL1_ING_BUF |
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_WRED_EN,
+ mask);
}
}
+ /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */
+ if (priv->switch_id == QCA8K_ID_QCA8327) {
+ mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) |
+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496);
+ qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH,
+ QCA8K_GLOBAL_FC_GOL_XON_THRES_S |
+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S,
+ mask);
+ }
+
/* Setup our port MTUs to match power on defaults */
for (i = 0; i < QCA8K_NUM_PORTS; i++)
priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
- qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
+ if (ret)
+ dev_warn(priv->dev, "failed setting MTU settings");
/* Flush the FDB table */
qca8k_fdb_flush(priv);
@@ -802,6 +1146,8 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
case 0: /* 1st CPU port */
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
state->interface != PHY_INTERFACE_MODE_SGMII)
return;
@@ -817,6 +1163,8 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
case 6: /* 2nd CPU port / external PHY */
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
state->interface != PHY_INTERFACE_MODE_SGMII &&
state->interface != PHY_INTERFACE_MODE_1000BASEX)
return;
@@ -840,16 +1188,22 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
break;
case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
/* RGMII_ID needs internal delay. This is enabled through
* PORT5_PAD_CTRL for all ports, rather than individual port
* registers
*/
qca8k_write(priv, reg,
QCA8K_PORT_PAD_RGMII_EN |
- QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
- QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
+ QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
+ QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
+ /* QCA8337 requires to set rgmii rx delay */
+ if (priv->switch_id == QCA8K_ID_QCA8337)
+ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
break;
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
@@ -903,6 +1257,8 @@ qca8k_phylink_validate(struct dsa_switch *ds, int port,
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
state->interface != PHY_INTERFACE_MODE_SGMII)
goto unsupported;
break;
@@ -913,13 +1269,16 @@ qca8k_phylink_validate(struct dsa_switch *ds, int port,
case 5:
/* Internal PHY */
if (state->interface != PHY_INTERFACE_MODE_NA &&
- state->interface != PHY_INTERFACE_MODE_GMII)
+ state->interface != PHY_INTERFACE_MODE_GMII &&
+ state->interface != PHY_INTERFACE_MODE_INTERNAL)
goto unsupported;
break;
case 6: /* 2nd CPU port / external PHY */
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
state->interface != PHY_INTERFACE_MODE_SGMII &&
state->interface != PHY_INTERFACE_MODE_1000BASEX)
goto unsupported;
@@ -957,6 +1316,8 @@ qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port,
u32 reg;
reg = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port));
+ if (reg < 0)
+ return reg;
state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP);
state->an_complete = state->link;
@@ -1057,18 +1418,26 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
const struct qca8k_mib_desc *mib;
- u32 reg, i;
+ u32 reg, i, val;
u64 hi;
for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) {
mib = &ar8327_mib[i];
reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset;
- data[i] = qca8k_read(priv, reg);
+ val = qca8k_read(priv, reg);
+ if (val < 0)
+ continue;
+
if (mib->size == 2) {
hi = qca8k_read(priv, reg + 4);
- data[i] |= hi << 32;
+ if (hi < 0)
+ continue;
}
+
+ data[i] = val;
+ if (mib->size == 2)
+ data[i] |= hi << 32;
}
}
@@ -1087,17 +1456,24 @@ qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee)
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port);
u32 reg;
+ int ret;
mutex_lock(&priv->reg_mutex);
reg = qca8k_read(priv, QCA8K_REG_EEE_CTRL);
+ if (reg < 0) {
+ ret = reg;
+ goto exit;
+ }
+
if (eee->eee_enabled)
reg |= lpi_en;
else
reg &= ~lpi_en;
- qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
- mutex_unlock(&priv->reg_mutex);
+ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
- return 0;
+exit:
+ mutex_unlock(&priv->reg_mutex);
+ return ret;
}
static int
@@ -1141,7 +1517,7 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
int port_mask = BIT(QCA8K_CPU_PORT);
- int i;
+ int i, ret;
for (i = 1; i < QCA8K_NUM_PORTS; i++) {
if (dsa_to_port(ds, i)->bridge_dev != br)
@@ -1149,17 +1525,20 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
/* Add this port to the portvlan mask of the other ports
* in the bridge
*/
- qca8k_reg_set(priv,
- QCA8K_PORT_LOOKUP_CTRL(i),
- BIT(port));
+ ret = qca8k_reg_set(priv,
+ QCA8K_PORT_LOOKUP_CTRL(i),
+ BIT(port));
+ if (ret)
+ return ret;
if (i != port)
port_mask |= BIT(i);
}
+
/* Add all other ports to this ports portvlan mask */
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_MEMBER, port_mask);
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_MEMBER, port_mask);
- return 0;
+ return ret;
}
static void
@@ -1223,9 +1602,7 @@ qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
mtu = priv->port_mtu[i];
/* Include L2 header / FCS length */
- qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
-
- return 0;
+ return qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
}
static int
@@ -1298,18 +1675,19 @@ qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
struct netlink_ext_ack *extack)
{
struct qca8k_priv *priv = ds->priv;
+ int ret;
if (vlan_filtering) {
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_VLAN_MODE,
- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_VLAN_MODE,
+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
} else {
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_VLAN_MODE,
- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_VLAN_MODE,
+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
}
- return 0;
+ return ret;
}
static int
@@ -1320,7 +1698,7 @@ qca8k_port_vlan_add(struct dsa_switch *ds, int port,
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
struct qca8k_priv *priv = ds->priv;
- int ret = 0;
+ int ret;
ret = qca8k_vlan_add(priv, port, vlan->vid, untagged);
if (ret) {
@@ -1331,14 +1709,17 @@ qca8k_port_vlan_add(struct dsa_switch *ds, int port,
if (pvid) {
int shift = 16 * (port % 2);
- qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
- 0xfff << shift, vlan->vid << shift);
- qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
- QCA8K_PORT_VLAN_CVID(vlan->vid) |
- QCA8K_PORT_VLAN_SVID(vlan->vid));
+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
+ 0xfff << shift, vlan->vid << shift);
+ if (ret)
+ return ret;
+
+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
+ QCA8K_PORT_VLAN_CVID(vlan->vid) |
+ QCA8K_PORT_VLAN_SVID(vlan->vid));
}
- return 0;
+ return ret;
}
static int
@@ -1346,7 +1727,7 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
struct qca8k_priv *priv = ds->priv;
- int ret = 0;
+ int ret;
ret = qca8k_vlan_del(priv, port, vlan->vid);
if (ret)
@@ -1355,6 +1736,22 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,
return ret;
}
+static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port)
+{
+ struct qca8k_priv *priv = ds->priv;
+
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
+
+ return 0;
+}
+
static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
@@ -1388,13 +1785,43 @@ static const struct dsa_switch_ops qca8k_switch_ops = {
.phylink_mac_config = qca8k_phylink_mac_config,
.phylink_mac_link_down = qca8k_phylink_mac_link_down,
.phylink_mac_link_up = qca8k_phylink_mac_link_up,
+ .get_phy_flags = qca8k_get_phy_flags,
};
+static int qca8k_read_switch_id(struct qca8k_priv *priv)
+{
+ const struct qca8k_match_data *data;
+ u32 val;
+ u8 id;
+
+ /* get the switches ID from the compatible */
+ data = of_device_get_match_data(priv->dev);
+ if (!data)
+ return -ENODEV;
+
+ val = qca8k_read(priv, QCA8K_REG_MASK_CTRL);
+ if (val < 0)
+ return -ENODEV;
+
+ id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK);
+ if (id != data->id) {
+ dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id);
+ return -ENODEV;
+ }
+
+ priv->switch_id = id;
+
+ /* Save revision to communicate to the internal PHY driver */
+ priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK);
+
+ return 0;
+}
+
static int
qca8k_sw_probe(struct mdio_device *mdiodev)
{
struct qca8k_priv *priv;
- u32 id;
+ int ret;
/* allocate the private data struct so that we can probe the switches
* ID register
@@ -1420,12 +1847,10 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
gpiod_set_value_cansleep(priv->reset_gpio, 0);
}
- /* read the switches ID register */
- id = qca8k_read(priv, QCA8K_REG_MASK_CTRL);
- id >>= QCA8K_MASK_CTRL_ID_S;
- id &= QCA8K_MASK_CTRL_ID_M;
- if (id != QCA8K_ID_QCA8337)
- return -ENODEV;
+ /* Check the detected switch id */
+ ret = qca8k_read_switch_id(priv);
+ if (ret)
+ return ret;
priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
if (!priv->ds)
@@ -1490,9 +1915,18 @@ static int qca8k_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
qca8k_suspend, qca8k_resume);
+static const struct qca8k_match_data qca832x = {
+ .id = QCA8K_ID_QCA8327,
+};
+
+static const struct qca8k_match_data qca833x = {
+ .id = QCA8K_ID_QCA8337,
+};
+
static const struct of_device_id qca8k_of_match[] = {
- { .compatible = "qca,qca8334" },
- { .compatible = "qca,qca8337" },
+ { .compatible = "qca,qca8327", .data = &qca832x },
+ { .compatible = "qca,qca8334", .data = &qca833x },
+ { .compatible = "qca,qca8337", .data = &qca833x },
{ /* sentinel */ },
};
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index 7ca4b93e0bb5..ed3b05ad6745 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -15,9 +15,13 @@
#define QCA8K_NUM_PORTS 7
#define QCA8K_MAX_MTU 9000
+#define PHY_ID_QCA8327 0x004dd034
+#define QCA8K_ID_QCA8327 0x12
#define PHY_ID_QCA8337 0x004dd036
#define QCA8K_ID_QCA8337 0x13
+#define QCA8K_BUSY_WAIT_TIMEOUT 2000
+
#define QCA8K_NUM_FDB_RECORDS 2048
#define QCA8K_CPU_PORT 0
@@ -26,18 +30,19 @@
/* Global control registers */
#define QCA8K_REG_MASK_CTRL 0x000
-#define QCA8K_MASK_CTRL_ID_M 0xff
-#define QCA8K_MASK_CTRL_ID_S 8
+#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0)
+#define QCA8K_MASK_CTRL_REV_ID(x) ((x) >> 0)
+#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8)
+#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8)
#define QCA8K_REG_PORT0_PAD_CTRL 0x004
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
#define QCA8K_PORT_PAD_RGMII_EN BIT(26)
-#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) \
- ((0x8 + (x & 0x3)) << 22)
-#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) \
- ((0x10 + (x & 0x3)) << 20)
-#define QCA8K_MAX_DELAY 3
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22)
+#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20)
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
+#define QCA8K_MAX_DELAY 3
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
#define QCA8K_REG_PWS 0x010
#define QCA8K_PWS_SERDES_AEN_DIS BIT(7)
@@ -164,6 +169,36 @@
#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16)
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
+#define QCA8K_REG_GLOBAL_FC_THRESH 0x800
+#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) ((x) << 16)
+#define QCA8K_GLOBAL_FC_GOL_XON_THRES_S GENMASK(24, 16)
+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) ((x) << 0)
+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S GENMASK(8, 0)
+
+#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF GENMASK(7, 4)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) ((x) << 4)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF GENMASK(11, 8)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) ((x) << 8)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF GENMASK(15, 12)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) ((x) << 12)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF GENMASK(19, 16)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) ((x) << 16)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF GENMASK(23, 20)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) ((x) << 20)
+#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF GENMASK(29, 24)
+#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) ((x) << 24)
+
+#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8)
+#define QCA8K_PORT_HOL_CTRL1_ING_BUF GENMASK(3, 0)
+#define QCA8K_PORT_HOL_CTRL1_ING(x) ((x) << 0)
+#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6)
+#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7)
+#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8)
+#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16)
+
/* Pkt edit registers */
#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2)))
@@ -211,7 +246,16 @@ struct ar8xxx_port_status {
int enabled;
};
+struct qca8k_match_data {
+ u8 id;
+};
+
struct qca8k_priv {
+ u8 switch_id;
+ u8 switch_revision;
+ u8 rgmii_tx_delay;
+ u8 rgmii_rx_delay;
+ bool legacy_phy_port_mapping;
struct regmap *regmap;
struct mii_bus *bus;
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index 741c67e546d4..7d7d3ffe25c3 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -1464,7 +1464,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
if (pdev) {
vp->pm_state_valid = 1;
pci_save_state(pdev);
- acpi_set_WOL(dev);
+ acpi_set_WOL(dev);
}
retval = register_netdev(dev);
if (retval == 0)
diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c
index 2488bfdb9133..8c321dfc7b3b 100644
--- a/drivers/net/ethernet/8390/axnet_cs.c
+++ b/drivers/net/ethernet/8390/axnet_cs.c
@@ -767,7 +767,7 @@ module_pcmcia_driver(axnet_cs_driver);
Paul Gortmaker : tweak ANK's above multicast changes a bit.
Paul Gortmaker : update packet statistics for v2.1.x
Alan Cox : support arbitrary stupid port mappings on the
- 68K Macintosh. Support >16bit I/O spaces
+ 68K Macintosh. Support >16bit I/O spaces
Paul Gortmaker : add kmod support for auto-loading of the 8390
module by all drivers that require it.
Alan Cox : Spinlocking work, added 'BUG_83C690'
@@ -1091,7 +1091,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
long e8390_base;
int interrupts, nr_serviced = 0, i;
struct ei_device *ei_local;
- int handled = 0;
+ int handled = 0;
unsigned long flags;
e8390_base = dev->base_addr;
@@ -1587,12 +1587,12 @@ static void do_set_multicast_list(struct net_device *dev)
}
outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
- if(dev->flags&IFF_PROMISC)
- outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
+ if(dev->flags&IFF_PROMISC)
+ outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev))
- outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
- else
- outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
+ outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
+ else
+ outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
}
diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
index 9d3b1e0e425c..cac036706382 100644
--- a/drivers/net/ethernet/8390/pcnet_cs.c
+++ b/drivers/net/ethernet/8390/pcnet_cs.c
@@ -1527,7 +1527,7 @@ static const struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
- PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
+ PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8010", 0x5070a7f9, 0x82f96e96),
PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8610", 0x5070a7f9, 0x86741224),
diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c
index 3fe3b4dfa7c5..1d8ed7357b7f 100644
--- a/drivers/net/ethernet/8390/smc-ultra.c
+++ b/drivers/net/ethernet/8390/smc-ultra.c
@@ -347,11 +347,11 @@ static int __init ultra_probe_isapnp(struct net_device *dev)
idev))) {
/* Avoid already found cards from previous calls */
if (pnp_device_attach(idev) < 0)
- continue;
+ continue;
if (pnp_activate_dev(idev) < 0) {
__again:
- pnp_device_detach(idev);
- continue;
+ pnp_device_detach(idev);
+ continue;
}
/* if no io and irq, search for next */
if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0))
diff --git a/drivers/net/ethernet/8390/stnic.c b/drivers/net/ethernet/8390/stnic.c
index 1f0670cd3ea3..fbbd7f22c142 100644
--- a/drivers/net/ethernet/8390/stnic.c
+++ b/drivers/net/ethernet/8390/stnic.c
@@ -114,7 +114,7 @@ static int __init stnic_probe(void)
/* New style probing API */
dev = alloc_ei_netdev();
if (!dev)
- return -ENOMEM;
+ return -ENOMEM;
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_get_node_addr (stnic_eadr);
diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c
index 1a7e4df9b3e9..9dc12b13061f 100644
--- a/drivers/net/ethernet/alteon/acenic.c
+++ b/drivers/net/ethernet/alteon/acenic.c
@@ -1883,16 +1883,16 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
}
}
- if (ACE_IS_TIGON_I(ap)) {
- struct cmd cmd;
- cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
- cmd.code = 0;
- cmd.idx = 0;
- ace_issue_cmd(ap->regs, &cmd);
- } else {
- writel(0, &((ap->regs)->RxJumboPrd));
- wmb();
- }
+ if (ACE_IS_TIGON_I(ap)) {
+ struct cmd cmd;
+ cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
+ cmd.code = 0;
+ cmd.idx = 0;
+ ace_issue_cmd(ap->regs, &cmd);
+ } else {
+ writel(0, &((ap->regs)->RxJumboPrd));
+ wmb();
+ }
ap->jumbo = 0;
ap->rx_jumbo_skbprd = 0;
@@ -2489,9 +2489,9 @@ restart:
}
}
- wmb();
- ap->tx_prd = idx;
- ace_set_txprd(regs, ap, idx);
+ wmb();
+ ap->tx_prd = idx;
+ ace_set_txprd(regs, ap, idx);
if (flagsize & BD_FLG_COAL_NOW) {
netif_stop_queue(dev);
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 4a1220cc6f10..9cac5aa75a73 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -19,14 +19,14 @@ Module Name:
Abstract:
- AMD8111 based 10/100 Ethernet Controller Driver.
+ AMD8111 based 10/100 Ethernet Controller Driver.
Environment:
Kernel Mode
Revision History:
- 3.0.0
+ 3.0.0
Initial Revision.
3.0.1
1. Dynamic interrupt coalescing.
diff --git a/drivers/net/ethernet/amd/amd8111e.h b/drivers/net/ethernet/amd/amd8111e.h
index 493f154eccf4..37da79da5f5e 100644
--- a/drivers/net/ethernet/amd/amd8111e.h
+++ b/drivers/net/ethernet/amd/amd8111e.h
@@ -10,14 +10,14 @@ Module Name:
Abstract:
- AMD8111 based 10/100 Ethernet Controller driver definitions.
+ AMD8111 based 10/100 Ethernet Controller driver definitions.
Environment:
Kernel Mode
Revision History:
- 3.0.0
+ 3.0.0
Initial Revision.
3.0.1
*/
@@ -692,7 +692,7 @@ enum coal_type{
};
enum coal_mode{
- RX_INTR_COAL,
+ RX_INTR_COAL,
TX_INTR_COAL,
DISABLE_COAL,
ENABLE_COAL,
diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index c1eab916438f..36f54d13a2eb 100644
--- a/drivers/net/ethernet/amd/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -706,7 +706,7 @@ static void lance_init_ring( struct net_device *dev )
CHECK_OFFSET(offset);
MEM->tx_head[i].base = offset;
MEM->tx_head[i].flag = TMD1_OWN_HOST;
- MEM->tx_head[i].base_hi = 0;
+ MEM->tx_head[i].base_hi = 0;
MEM->tx_head[i].length = 0;
MEM->tx_head[i].misc = 0;
offset += PKT_BUF_SZ;
diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c
index 7282ce55ffb8..493b0cefcc2a 100644
--- a/drivers/net/ethernet/amd/declance.c
+++ b/drivers/net/ethernet/amd/declance.c
@@ -937,7 +937,7 @@ static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return NETDEV_TX_OK;
+ return NETDEV_TX_OK;
}
static void lance_load_multicast(struct net_device *dev)
diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c
index aff44241988c..2178e6b89dbd 100644
--- a/drivers/net/ethernet/amd/lance.c
+++ b/drivers/net/ethernet/amd/lance.c
@@ -780,7 +780,7 @@ lance_open(struct net_device *dev)
outw(0x0002, ioaddr+LANCE_ADDR);
/* Only touch autoselect bit. */
outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
- }
+ }
if (lance_debug > 1)
printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
@@ -812,7 +812,7 @@ lance_open(struct net_device *dev)
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* reports that doing so triggers a bug in the '974.
*/
- outw(0x0042, ioaddr+LANCE_DATA);
+ outw(0x0042, ioaddr+LANCE_DATA);
if (lance_debug > 2)
printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n",
diff --git a/drivers/net/ethernet/amd/ni65.c b/drivers/net/ethernet/amd/ni65.c
index c38edf6f03a3..5c1cfb0c4a42 100644
--- a/drivers/net/ethernet/amd/ni65.c
+++ b/drivers/net/ethernet/amd/ni65.c
@@ -193,7 +193,7 @@ static struct card {
.vendor_id = ni_vendor,
.cardname = "ni6510",
.config = 0x1,
- },
+ },
{
.id0 = NI65_EB_ID0,
.id1 = NI65_EB_ID1,
@@ -204,7 +204,7 @@ static struct card {
.vendor_id = ni_vendor,
.cardname = "ni6510 EtherBlaster",
.config = 0x2,
- },
+ },
{
.id0 = NE2100_ID0,
.id1 = NE2100_ID1,
@@ -1232,15 +1232,15 @@ MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)");
int __init init_module(void)
{
- dev_ni65 = ni65_probe(-1);
+ dev_ni65 = ni65_probe(-1);
return PTR_ERR_OR_ZERO(dev_ni65);
}
void __exit cleanup_module(void)
{
- unregister_netdev(dev_ni65);
- cleanup_card(dev_ni65);
- free_netdev(dev_ni65);
+ unregister_netdev(dev_ni65);
+ cleanup_card(dev_ni65);
+ free_netdev(dev_ni65);
}
#endif /* MODULE */
diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
index 11c0b13edd30..4019cab87505 100644
--- a/drivers/net/ethernet/amd/nmclan_cs.c
+++ b/drivers/net/ethernet/amd/nmclan_cs.c
@@ -541,7 +541,7 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
if(++ct > 500)
{
pr_err("reset failed, card removed?\n");
- return -1;
+ return -1;
}
udelay(1);
}
@@ -585,11 +585,11 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
ct = 0;
while (mace_read(lp, ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG)
{
- if(++ ct > 500)
- {
+ if(++ ct > 500)
+ {
pr_err("ADDRCHG timeout, card removed?\n");
- return -1;
- }
+ return -1;
+ }
}
/* Set PADR register */
for (i = 0; i < ETH_ALEN; i++)
@@ -655,7 +655,7 @@ static int nmclan_config(struct pcmcia_device *link)
}
if(mace_init(lp, ioaddr, dev->dev_addr) == -1)
- goto failed;
+ goto failed;
/* The if_port symbol can be set when the module is loaded */
if (if_port <= 2)
diff --git a/drivers/net/ethernet/amd/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c
index 00ae1081254d..f8d7a9387a56 100644
--- a/drivers/net/ethernet/amd/sun3lance.c
+++ b/drivers/net/ethernet/amd/sun3lance.c
@@ -150,7 +150,7 @@ struct lance_memory {
struct lance_private {
volatile unsigned short *iobase;
struct lance_memory *mem;
- int new_rx, new_tx; /* The next free ring entry */
+ int new_rx, new_tx; /* The next free ring entry */
int old_tx, old_rx; /* ring entry to be processed */
/* These two must be longs for set_bit() */
long tx_full;
@@ -465,7 +465,7 @@ static void lance_init_ring( struct net_device *dev )
for( i = 0; i < TX_RING_SIZE; i++ ) {
MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]);
MEM->tx_head[i].flag = 0;
- MEM->tx_head[i].base_hi =
+ MEM->tx_head[i].base_hi =
(dvma_vtob(MEM->tx_data[i])) >>16;
MEM->tx_head[i].length = 0;
MEM->tx_head[i].misc = 0;
@@ -581,8 +581,8 @@ lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
AREG = CSR0;
- DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
- dev->name, DREG ));
+ DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
+ dev->name, DREG ));
#ifdef CONFIG_SUN3X
/* this weirdness doesn't appear on sun3... */
@@ -636,8 +636,8 @@ lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Trigger an immediate send poll. */
REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
AREG = CSR0;
- DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
- dev->name, DREG ));
+ DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
+ dev->name, DREG ));
dev_kfree_skb(skb);
lp->lock = 0;
diff --git a/drivers/net/ethernet/apple/bmac.c b/drivers/net/ethernet/apple/bmac.c
index 1e4e402f07d7..a989d2df59ad 100644
--- a/drivers/net/ethernet/apple/bmac.c
+++ b/drivers/net/ethernet/apple/bmac.c
@@ -477,26 +477,26 @@ static int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
config = bmread(dev, RXCFG);
bmwrite(dev, RXCFG, (config & ~RxMACEnable));
config = bmread(dev, TXCFG);
- bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+ bmwrite(dev, TXCFG, (config & ~TxMACEnable));
bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
- /* disable rx and tx dma */
+ /* disable rx and tx dma */
rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */
td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */
- /* free some skb's */
- for (i=0; i<N_RX_RING; i++) {
- if (bp->rx_bufs[i] != NULL) {
- dev_kfree_skb(bp->rx_bufs[i]);
- bp->rx_bufs[i] = NULL;
- }
- }
- for (i = 0; i<N_TX_RING; i++) {
+ /* free some skb's */
+ for (i=0; i<N_RX_RING; i++) {
+ if (bp->rx_bufs[i] != NULL) {
+ dev_kfree_skb(bp->rx_bufs[i]);
+ bp->rx_bufs[i] = NULL;
+ }
+ }
+ for (i = 0; i<N_TX_RING; i++) {
if (bp->tx_bufs[i] != NULL) {
dev_kfree_skb(bp->tx_bufs[i]);
bp->tx_bufs[i] = NULL;
}
}
}
- pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
+ pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
return 0;
}
@@ -510,9 +510,9 @@ static int bmac_resume(struct macio_dev *mdev)
bmac_reset_and_enable(dev);
enable_irq(dev->irq);
- enable_irq(bp->tx_dma_intr);
- enable_irq(bp->rx_dma_intr);
- netif_device_attach(dev);
+ enable_irq(bp->tx_dma_intr);
+ enable_irq(bp->rx_dma_intr);
+ netif_device_attach(dev);
return 0;
}
@@ -1599,7 +1599,7 @@ static int bmac_remove(struct macio_dev *mdev)
unregister_netdev(dev);
- free_irq(dev->irq, dev);
+ free_irq(dev->irq, dev);
free_irq(bp->tx_dma_intr, dev);
free_irq(bp->rx_dma_intr, dev);
diff --git a/drivers/net/ethernet/apple/mace.c b/drivers/net/ethernet/apple/mace.c
index 9e5006e59215..4b80e3a52a19 100644
--- a/drivers/net/ethernet/apple/mace.c
+++ b/drivers/net/ethernet/apple/mace.c
@@ -364,9 +364,9 @@ static void mace_reset(struct net_device *dev)
out_8(&mb->iac, 0);
if (mp->port_aaui)
- out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO);
+ out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO);
else
- out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
+ out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
}
static void __mace_set_address(struct net_device *dev, void *addr)
@@ -378,9 +378,9 @@ static void __mace_set_address(struct net_device *dev, void *addr)
/* load up the hardware address */
if (mp->chipid == BROKEN_ADDRCHG_REV)
- out_8(&mb->iac, PHYADDR);
+ out_8(&mb->iac, PHYADDR);
else {
- out_8(&mb->iac, ADDRCHG | PHYADDR);
+ out_8(&mb->iac, ADDRCHG | PHYADDR);
while ((in_8(&mb->iac) & ADDRCHG) != 0)
;
}
diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c
index 48ecdf15eddc..1c9ca3bcb871 100644
--- a/drivers/net/ethernet/arc/emac_rockchip.c
+++ b/drivers/net/ethernet/arc/emac_rockchip.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/**
+/*
* emac-rockchip.c - Rockchip EMAC specific glue layer
*
* Copyright (C) 2014 Romain Perier <[email protected]>
diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h
index 9d0e74f6b089..693006c5a498 100644
--- a/drivers/net/ethernet/atheros/alx/alx.h
+++ b/drivers/net/ethernet/atheros/alx/alx.h
@@ -137,6 +137,8 @@ struct alx_priv {
/* protects hw.stats */
spinlock_t stats_lock;
+
+ struct mutex mtx;
};
extern const struct ethtool_ops alx_ethtool_ops;
diff --git a/drivers/net/ethernet/atheros/alx/ethtool.c b/drivers/net/ethernet/atheros/alx/ethtool.c
index 2f4eabf652e8..b716adacd815 100644
--- a/drivers/net/ethernet/atheros/alx/ethtool.c
+++ b/drivers/net/ethernet/atheros/alx/ethtool.c
@@ -163,8 +163,10 @@ static int alx_get_link_ksettings(struct net_device *netdev,
}
}
+ mutex_lock(&alx->mtx);
cmd->base.speed = hw->link_speed;
cmd->base.duplex = hw->duplex;
+ mutex_unlock(&alx->mtx);
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
supported);
@@ -181,8 +183,7 @@ static int alx_set_link_ksettings(struct net_device *netdev,
struct alx_hw *hw = &alx->hw;
u32 adv_cfg;
u32 advertising;
-
- ASSERT_RTNL();
+ int ret;
ethtool_convert_link_mode_to_legacy_u32(&advertising,
cmd->link_modes.advertising);
@@ -200,7 +201,12 @@ static int alx_set_link_ksettings(struct net_device *netdev,
}
hw->adv_cfg = adv_cfg;
- return alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl);
+
+ mutex_lock(&alx->mtx);
+ ret = alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl);
+ mutex_unlock(&alx->mtx);
+
+ return ret;
}
static void alx_get_pauseparam(struct net_device *netdev,
@@ -209,10 +215,12 @@ static void alx_get_pauseparam(struct net_device *netdev,
struct alx_priv *alx = netdev_priv(netdev);
struct alx_hw *hw = &alx->hw;
+ mutex_lock(&alx->mtx);
pause->autoneg = !!(hw->flowctrl & ALX_FC_ANEG &&
hw->adv_cfg & ADVERTISED_Autoneg);
pause->tx_pause = !!(hw->flowctrl & ALX_FC_TX);
pause->rx_pause = !!(hw->flowctrl & ALX_FC_RX);
+ mutex_unlock(&alx->mtx);
}
@@ -232,7 +240,7 @@ static int alx_set_pauseparam(struct net_device *netdev,
if (pause->autoneg)
fc |= ALX_FC_ANEG;
- ASSERT_RTNL();
+ mutex_lock(&alx->mtx);
/* restart auto-neg for auto-mode */
if (hw->adv_cfg & ADVERTISED_Autoneg) {
@@ -245,8 +253,10 @@ static int alx_set_pauseparam(struct net_device *netdev,
if (reconfig_phy) {
err = alx_setup_speed_duplex(hw, hw->adv_cfg, fc);
- if (err)
+ if (err) {
+ mutex_unlock(&alx->mtx);
return err;
+ }
}
/* flow control on mac */
@@ -254,6 +264,7 @@ static int alx_set_pauseparam(struct net_device *netdev,
alx_cfg_mac_flowcontrol(hw, fc);
hw->flowctrl = fc;
+ mutex_unlock(&alx->mtx);
return 0;
}
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index b3d74332ed33..45e380f3b065 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Johannes Berg <[email protected]>
+ * Copyright (c) 2013, 2021 Johannes Berg <[email protected]>
*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -1091,8 +1091,9 @@ static int alx_init_sw(struct alx_priv *alx)
ALX_MAC_CTRL_RXFC_EN |
ALX_MAC_CTRL_TXFC_EN |
7 << ALX_MAC_CTRL_PRMBLEN_SHIFT;
+ mutex_init(&alx->mtx);
- return err;
+ return 0;
}
@@ -1122,6 +1123,8 @@ static void alx_halt(struct alx_priv *alx)
{
struct alx_hw *hw = &alx->hw;
+ lockdep_assert_held(&alx->mtx);
+
alx_netif_stop(alx);
hw->link_speed = SPEED_UNKNOWN;
hw->duplex = DUPLEX_UNKNOWN;
@@ -1147,6 +1150,8 @@ static void alx_configure(struct alx_priv *alx)
static void alx_activate(struct alx_priv *alx)
{
+ lockdep_assert_held(&alx->mtx);
+
/* hardware setting lost, restore it */
alx_reinit_rings(alx);
alx_configure(alx);
@@ -1161,7 +1166,7 @@ static void alx_activate(struct alx_priv *alx)
static void alx_reinit(struct alx_priv *alx)
{
- ASSERT_RTNL();
+ lockdep_assert_held(&alx->mtx);
alx_halt(alx);
alx_activate(alx);
@@ -1249,6 +1254,8 @@ out_disable_adv_intr:
static void __alx_stop(struct alx_priv *alx)
{
+ lockdep_assert_held(&alx->mtx);
+
alx_free_irq(alx);
cancel_work_sync(&alx->link_check_wk);
@@ -1284,6 +1291,8 @@ static void alx_check_link(struct alx_priv *alx)
int old_speed;
int err;
+ lockdep_assert_held(&alx->mtx);
+
/* clear PHY internal interrupt status, otherwise the main
* interrupt status will be asserted forever
*/
@@ -1338,12 +1347,24 @@ reset:
static int alx_open(struct net_device *netdev)
{
- return __alx_open(netdev_priv(netdev), false);
+ struct alx_priv *alx = netdev_priv(netdev);
+ int ret;
+
+ mutex_lock(&alx->mtx);
+ ret = __alx_open(alx, false);
+ mutex_unlock(&alx->mtx);
+
+ return ret;
}
static int alx_stop(struct net_device *netdev)
{
- __alx_stop(netdev_priv(netdev));
+ struct alx_priv *alx = netdev_priv(netdev);
+
+ mutex_lock(&alx->mtx);
+ __alx_stop(alx);
+ mutex_unlock(&alx->mtx);
+
return 0;
}
@@ -1353,18 +1374,18 @@ static void alx_link_check(struct work_struct *work)
alx = container_of(work, struct alx_priv, link_check_wk);
- rtnl_lock();
+ mutex_lock(&alx->mtx);
alx_check_link(alx);
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
}
static void alx_reset(struct work_struct *work)
{
struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk);
- rtnl_lock();
+ mutex_lock(&alx->mtx);
alx_reinit(alx);
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
}
static int alx_tpd_req(struct sk_buff *skb)
@@ -1771,6 +1792,8 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_unmap;
}
+ mutex_lock(&alx->mtx);
+
alx_reset_pcie(hw);
phy_configured = alx_phy_configured(hw);
@@ -1781,7 +1804,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = alx_reset_mac(hw);
if (err) {
dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err);
- goto out_unmap;
+ goto out_unlock;
}
/* setup link to put it in a known good starting state */
@@ -1791,7 +1814,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev,
"failed to configure PHY speed/duplex (err=%d)\n",
err);
- goto out_unmap;
+ goto out_unlock;
}
}
@@ -1824,9 +1847,11 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!alx_get_phy_info(hw)) {
dev_err(&pdev->dev, "failed to identify PHY\n");
err = -EIO;
- goto out_unmap;
+ goto out_unlock;
}
+ mutex_unlock(&alx->mtx);
+
INIT_WORK(&alx->link_check_wk, alx_link_check);
INIT_WORK(&alx->reset_wk, alx_reset);
netif_carrier_off(netdev);
@@ -1843,6 +1868,8 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
+out_unlock:
+ mutex_unlock(&alx->mtx);
out_unmap:
iounmap(hw->hw_addr);
out_free_netdev:
@@ -1869,6 +1896,8 @@ static void alx_remove(struct pci_dev *pdev)
pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
+ mutex_destroy(&alx->mtx);
+
free_netdev(alx->dev);
}
@@ -1880,7 +1909,11 @@ static int alx_suspend(struct device *dev)
if (!netif_running(alx->dev))
return 0;
netif_device_detach(alx->dev);
+
+ mutex_lock(&alx->mtx);
__alx_stop(alx);
+ mutex_unlock(&alx->mtx);
+
return 0;
}
@@ -1890,20 +1923,23 @@ static int alx_resume(struct device *dev)
struct alx_hw *hw = &alx->hw;
int err;
+ mutex_lock(&alx->mtx);
alx_reset_phy(hw);
- if (!netif_running(alx->dev))
- return 0;
+ if (!netif_running(alx->dev)) {
+ err = 0;
+ goto unlock;
+ }
- rtnl_lock();
err = __alx_open(alx, true);
- rtnl_unlock();
if (err)
- return err;
+ goto unlock;
netif_device_attach(alx->dev);
- return 0;
+unlock:
+ mutex_unlock(&alx->mtx);
+ return err;
}
static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
@@ -1922,7 +1958,7 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
dev_info(&pdev->dev, "pci error detected\n");
- rtnl_lock();
+ mutex_lock(&alx->mtx);
if (netif_running(netdev)) {
netif_device_detach(netdev);
@@ -1934,7 +1970,7 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
else
pci_disable_device(pdev);
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
return rc;
}
@@ -1947,7 +1983,7 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev)
dev_info(&pdev->dev, "pci error slot reset\n");
- rtnl_lock();
+ mutex_lock(&alx->mtx);
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n");
@@ -1960,7 +1996,7 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev)
if (!alx_reset_mac(hw))
rc = PCI_ERS_RESULT_RECOVERED;
out:
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
return rc;
}
@@ -1972,14 +2008,14 @@ static void alx_pci_error_resume(struct pci_dev *pdev)
dev_info(&pdev->dev, "pci error resume\n");
- rtnl_lock();
+ mutex_lock(&alx->mtx);
if (netif_running(netdev)) {
alx_activate(alx);
netif_device_attach(netdev);
}
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
}
static const struct pci_error_handlers alx_err_handlers = {
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h
index 28ae5c16831e..9d70cb7544f1 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h
@@ -241,6 +241,8 @@ struct atl1c_tpd_ext_desc {
#define RRS_PACKET_PROT_IS_IPV6_ONLY(word) \
((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 6)
+#define RRS_MT_PROT_ID_TCPUDP BIT(19)
+
struct atl1c_recv_ret_status {
__le32 word0;
__le32 rss_hash;
@@ -289,6 +291,7 @@ enum atl1c_nic_type {
athr_l2c_b2,
athr_l1d,
athr_l1d_2,
+ athr_mt,
};
enum atl1c_trans_queue {
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index 140358dcf61e..7dff20350865 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
@@ -636,6 +636,23 @@ int atl1c_phy_init(struct atl1c_hw *hw)
return 0;
}
+bool atl1c_get_link_status(struct atl1c_hw *hw)
+{
+ u16 phy_data;
+
+ if (hw->nic_type == athr_mt) {
+ u32 spd;
+
+ AT_READ_REG(hw, REG_MT_SPEED, &spd);
+ return !!spd;
+ }
+
+ /* MII_BMSR must be read twice */
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ return !!(phy_data & BMSR_LSTATUS);
+}
+
/*
* Detects the current speed and duplex settings of the hardware.
*
@@ -648,6 +665,15 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
int err;
u16 phy_data;
+ if (hw->nic_type == athr_mt) {
+ u32 spd;
+
+ AT_READ_REG(hw, REG_MT_SPEED, &spd);
+ *speed = spd;
+ *duplex = FULL_DUPLEX;
+ return 0;
+ }
+
/* Read PHY Specific Status Register (17) */
err = atl1c_read_phy_reg(hw, MII_GIGA_PSSR, &phy_data);
if (err)
@@ -686,15 +712,12 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
int ret = 0;
u16 autoneg_advertised = ADVERTISED_10baseT_Half;
u16 save_autoneg_advertised;
- u16 phy_data;
u16 mii_lpa_data;
u16 speed = SPEED_0;
u16 duplex = FULL_DUPLEX;
int i;
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- if (phy_data & BMSR_LSTATUS) {
+ if (atl1c_get_link_status(hw)) {
atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
if (mii_lpa_data & LPA_10FULL)
autoneg_advertised = ADVERTISED_10baseT_Full;
@@ -717,9 +740,7 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
if (mii_lpa_data) {
for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
mdelay(100);
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- if (phy_data & BMSR_LSTATUS) {
+ if (atl1c_get_link_status(hw)) {
if (atl1c_get_speed_and_duplex(hw, &speed,
&duplex) != 0)
dev_dbg(&pdev->dev,
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
index ce1a123dce2c..c263b326cec5 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
@@ -26,6 +26,7 @@ void atl1c_phy_disable(struct atl1c_hw *hw);
void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr);
int atl1c_phy_reset(struct atl1c_hw *hw);
int atl1c_read_mac_addr(struct atl1c_hw *hw);
+bool atl1c_get_link_status(struct atl1c_hw *hw);
int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex);
u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr);
void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value);
@@ -764,6 +765,13 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define REG_DEBUG_DATA0 0x1900
#define REG_DEBUG_DATA1 0x1904
+#define REG_MT_MAGIC 0x1F00
+#define REG_MT_MODE 0x1F04
+#define REG_MT_SPEED 0x1F08
+#define REG_MT_VERSION 0x1F0C
+
+#define MT_MAGIC 0xaabb1234
+
#define L1D_MPW_PHYID1 0xD01C /* V7 */
#define L1D_MPW_PHYID2 0xD01D /* V1-V6 */
#define L1D_MPW_PHYID3 0xD01E /* V8 */
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index c6263cf8d3c0..77da1c54c49f 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -232,15 +232,14 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
int err;
unsigned long flags;
- u16 speed, duplex, phy_data;
+ u16 speed, duplex;
+ bool link;
spin_lock_irqsave(&adapter->mdio_lock, flags);
- /* MII_BMSR must read twise */
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ link = atl1c_get_link_status(hw);
spin_unlock_irqrestore(&adapter->mdio_lock, flags);
- if ((phy_data & BMSR_LSTATUS) == 0) {
+ if (!link) {
/* link down */
netif_carrier_off(netdev);
hw->hibernate = true;
@@ -284,16 +283,13 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- u16 phy_data;
- u16 link_up;
+ bool link;
spin_lock(&adapter->mdio_lock);
- atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
- atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ link = atl1c_get_link_status(&adapter->hw);
spin_unlock(&adapter->mdio_lock);
- link_up = phy_data & BMSR_LSTATUS;
/* notify upper layer link down ASAP */
- if (!link_up) {
+ if (!link) {
if (netif_carrier_ok(netdev)) {
/* old link state: Up */
netif_carrier_off(netdev);
@@ -436,7 +432,7 @@ static void atl1c_restore_vlan(struct atl1c_adapter *adapter)
}
/**
- * atl1c_set_mac - Change the Ethernet Address of the NIC
+ * atl1c_set_mac_addr - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
* @p: pointer to an address structure
*
@@ -478,6 +474,9 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
static netdev_features_t atl1c_fix_features(struct net_device *netdev,
netdev_features_t features)
{
+ struct atl1c_adapter *adapter = netdev_priv(netdev);
+ struct atl1c_hw *hw = &adapter->hw;
+
/*
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
@@ -487,8 +486,10 @@ static netdev_features_t atl1c_fix_features(struct net_device *netdev,
else
features &= ~NETIF_F_HW_VLAN_CTAG_TX;
- if (netdev->mtu > MAX_TSO_FRAME_SIZE)
- features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ if (hw->nic_type != athr_mt) {
+ if (netdev->mtu > MAX_TSO_FRAME_SIZE)
+ features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ }
return features;
}
@@ -515,9 +516,12 @@ static void atl1c_set_max_mtu(struct net_device *netdev)
case athr_l1d:
case athr_l1d_2:
netdev->max_mtu = MAX_JUMBO_FRAME_SIZE -
- (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
+ (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
break;
- /* The 10/100 devices don't support jumbo packets, max_mtu 1500 */
+ case athr_mt:
+ netdev->max_mtu = 9500;
+ break;
+ /* The 10/100 devices don't support jumbo packets, max_mtu 1500 */
default:
netdev->max_mtu = ETH_DATA_LEN;
break;
@@ -644,6 +648,7 @@ static int atl1c_alloc_queues(struct atl1c_adapter *adapter)
static void atl1c_set_mac_type(struct atl1c_hw *hw)
{
+ u32 magic;
switch (hw->device_id) {
case PCI_DEVICE_ID_ATTANSIC_L2C:
hw->nic_type = athr_l2c;
@@ -662,6 +667,9 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
break;
case PCI_DEVICE_ID_ATHEROS_L1D_2_0:
hw->nic_type = athr_l1d_2;
+ AT_READ_REG(hw, REG_MT_MAGIC, &magic);
+ if (magic == MT_MAGIC)
+ hw->nic_type = athr_mt;
break;
default:
break;
@@ -952,7 +960,7 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
}
/**
- * atl1c_setup_mem_resources - allocate Tx / RX descriptor resources
+ * atl1c_setup_ring_resources - allocate Tx / RX descriptor resources
* @adapter: board private structure
*
* Return 0 on success, negative on failure
@@ -1358,7 +1366,7 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed)
}
/**
- * atl1c_configure - Configure Transmit&Receive Unit after Reset
+ * atl1c_configure_mac - Configure Transmit&Receive Unit after Reset
* @adapter: board private structure
*
* Configure the Tx /Rx unit of the MAC after a reset.
@@ -1659,6 +1667,11 @@ static irqreturn_t atl1c_intr(int irq, void *data)
static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
struct sk_buff *skb, struct atl1c_recv_ret_status *prrs)
{
+ if (adapter->hw.nic_type == athr_mt) {
+ if (prrs->word3 & RRS_MT_PROT_ID_TCPUDP)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ return;
+ }
/*
* The pid field in RRS in not correct sometimes, so we
* cannot figure out if the packet is fragmented or not,
@@ -2207,8 +2220,8 @@ err_dma:
return -1;
}
-static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb,
- struct atl1c_tpd_desc *tpd, enum atl1c_trans_queue type)
+static void atl1c_tx_queue(struct atl1c_adapter *adapter,
+ enum atl1c_trans_queue type)
{
struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
u16 reg;
@@ -2234,6 +2247,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
if (atl1c_tpd_avail(adapter, type) < tpd_req) {
/* no enough descriptor, just stop queue */
+ atl1c_tx_queue(adapter, type);
netif_stop_queue(netdev);
return NETDEV_TX_BUSY;
}
@@ -2242,6 +2256,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
/* do TSO and check sum */
if (atl1c_tso_csum(adapter, skb, &tpd, type) != 0) {
+ atl1c_tx_queue(adapter, type);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -2266,8 +2281,10 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
atl1c_tx_rollback(adapter, tpd, type);
dev_kfree_skb_any(skb);
} else {
- netdev_sent_queue(adapter->netdev, skb->len);
- atl1c_tx_queue(adapter, skb, tpd, type);
+ bool more = netdev_xmit_more();
+
+ if (__netdev_sent_queue(adapter->netdev, skb->len, more))
+ atl1c_tx_queue(adapter, type);
}
return NETDEV_TX_OK;
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index ff9f96de74b8..2eb0a2ab69f6 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -357,7 +357,7 @@ static void atl1e_restore_vlan(struct atl1e_adapter *adapter)
}
/**
- * atl1e_set_mac - Change the Ethernet Address of the NIC
+ * atl1e_set_mac_addr - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
* @p: pointer to an address structure
*
@@ -787,7 +787,7 @@ static void atl1e_free_ring_resources(struct atl1e_adapter *adapter)
}
/**
- * atl1e_setup_mem_resources - allocate Tx / RX descriptor resources
+ * atl1e_setup_ring_resources - allocate Tx / RX descriptor resources
* @adapter: board private structure
*
* Return 0 on success, negative on failure
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index eaf96d002fa5..c67201a13cf5 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -1011,7 +1011,7 @@ static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
}
/**
- * atl1_setup_mem_resources - allocate Tx / RX descriptor resources
+ * atl1_setup_ring_resources - allocate Tx / RX descriptor resources
* @adapter: board private structure
*
* Return 0 on success, negative on failure
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index b455b60a5434..ad2655efe423 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -1556,8 +1556,8 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
B44_ETHIPV4UDP_HLEN);
- bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
- bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
/* Raw ethernet II magic packet pattern - pattern 1 */
memset(pwol_pattern, 0, B44_PATTERN_SIZE);
@@ -1565,9 +1565,9 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
ETH_HLEN);
- bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
B44_PATTERN_BASE + B44_PATTERN_SIZE);
- bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
B44_PMASK_BASE + B44_PMASK_SIZE);
/* Ipv6 magic packet pattern - pattern 2 */
@@ -1576,9 +1576,9 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
B44_ETHIPV6UDP_HLEN);
- bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE);
- bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE);
kfree(pwol_pattern);
@@ -1631,9 +1631,9 @@ static void b44_setup_wol(struct b44 *bp)
val = br32(bp, B44_DEVCTRL);
bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
- } else {
- b44_setup_pseudo_magicp(bp);
- }
+ } else {
+ b44_setup_pseudo_magicp(bp);
+ }
b44_setup_wol_pci(bp);
}
@@ -1757,7 +1757,7 @@ static void __b44_set_rx_mode(struct net_device *dev)
__b44_cam_write(bp, zero, i);
bw32(bp, B44_RXCONFIG, val);
- val = br32(bp, B44_CAM_CTRL);
+ val = br32(bp, B44_CAM_CTRL);
bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
}
}
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index c0986096c701..2c5f36befdfe 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -572,7 +572,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
}
if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
- ret = -EBUSY;
+ ret = -EBUSY;
else
ret = 0;
@@ -3599,7 +3599,7 @@ bnx2_set_rx_mode(struct net_device *dev)
for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
0xffffffff);
- }
+ }
sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
}
else {
@@ -4674,7 +4674,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
if (addr == page_end-4) {
cmd_flags = BNX2_NVM_COMMAND_LAST;
- }
+ }
rc = bnx2_nvram_write_dword(bp, addr,
&flash_buffer[i], cmd_flags);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 281b1c2e04a7..2acbc73dcd18 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -13586,7 +13586,7 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
}
/**
- * bnx2x_get_num_none_def_sbs - return the number of none default SBs
+ * bnx2x_get_num_non_def_sbs - return the number of none default SBs
* @pdev: pci device
* @cnic_cnt: count
*
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 6cd1523ad9e5..542c69822649 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -4152,7 +4152,7 @@ void bnx2x_init_mcast_obj(struct bnx2x *bp,
/*************************** Credit handling **********************************/
/**
- * atomic_add_ifless - add if the result is less than a given value.
+ * __atomic_add_ifless - add if the result is less than a given value.
*
* @v: pointer of type atomic_t
* @a: the amount to add to v...
@@ -4180,7 +4180,7 @@ static inline bool __atomic_add_ifless(atomic_t *v, int a, int u)
}
/**
- * atomic_dec_ifmoe - dec if the result is more or equal than a given value.
+ * __atomic_dec_ifmoe - dec if the result is more or equal than a given value.
*
* @v: pointer of type atomic_t
* @a: the amount to dec from v...
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cee.c b/drivers/net/ethernet/brocade/bna/bfa_cee.c
index 06f221c44802..eeb05e31713f 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cee.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.c
@@ -82,7 +82,7 @@ bfa_cee_get_attr_isr(struct bfa_cee *cee, enum bfa_status status)
}
/**
- * bfa_cee_get_attr_isr - CEE ISR for get-stats responses from f/w
+ * bfa_cee_get_stats_isr - CEE ISR for get-stats responses from f/w
*
* @cee: Pointer to the CEE module
* @status: Return status from the f/w
diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
index 353393dea639..8b7b59908a1a 100644
--- a/drivers/net/ethernet/cadence/macb_pci.c
+++ b/drivers/net/ethernet/cadence/macb_pci.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* DOC: Cadence GEM PCI wrapper.
*
* Copyright (C) 2016 Cadence Design Systems - https://www.cadence.com
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index 283918aeb741..5c368a9cbbbc 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* 1588 PTP support for Cadence GEM device.
*
* Copyright (C) 2017 Cadence Design Systems - https://www.cadence.com
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index bbb453c6a5f7..b6a066404f4b 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -711,7 +711,7 @@ static void xgmac_rx_refill(struct xgmac_priv *priv)
}
/**
- * init_xgmac_dma_desc_rings - init the RX/TX descriptor rings
+ * xgmac_dma_desc_rings_init - init the RX/TX descriptor rings
* @dev: net device structure
* Description: this function initializes the DMA RX/TX descriptors
* and allocates the socket buffers.
@@ -859,7 +859,7 @@ static void xgmac_free_dma_desc_rings(struct xgmac_priv *priv)
}
/**
- * xgmac_tx:
+ * xgmac_tx_complete:
* @priv: private driver structure
* Description: it reclaims resources after transmission completes.
*/
@@ -1040,7 +1040,7 @@ static int xgmac_open(struct net_device *dev)
}
/**
- * xgmac_release - close entry point of the driver
+ * xgmac_stop - close entry point of the driver
* @dev : device pointer.
* Description:
* This is the stop entry point of the driver.
@@ -1812,7 +1812,7 @@ err_alloc:
}
/**
- * xgmac_dvr_remove
+ * xgmac_remove
* @pdev: platform device pointer
* Description: this function resets the TX/RX processes, disables the MAC RX/TX
* changes the link status, releases the DMA descriptor rings,
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
index 0c783aadf393..c36fed9c3d73 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -594,9 +594,6 @@ static void bgx_lmac_handler(struct net_device *netdev)
struct phy_device *phydev;
int link_changed = 0;
- if (!lmac)
- return;
-
phydev = lmac->phydev;
if (!phydev->link && lmac->last_link)
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index 1cc3c51eff71..11d3b6218ed7 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -665,7 +665,7 @@ static void t3_reset_qset(struct sge_qset *q)
/**
- * free_qset - free the resources of an SGE queue set
+ * t3_free_qset - free the resources of an SGE queue set
* @adapter: the adapter owning the queue set
* @q: the queue set
*
@@ -1256,7 +1256,7 @@ static inline void t3_stop_tx_queue(struct netdev_queue *txq,
}
/**
- * eth_xmit - add a packet to the Ethernet Tx queue
+ * t3_eth_xmit - add a packet to the Ethernet Tx queue
* @skb: the packet
* @dev: the egress net device
*
@@ -3371,7 +3371,7 @@ void t3_sge_prep(struct adapter *adap, struct sge_params *p)
q->coalesce_usecs = 5;
q->rspq_size = 1024;
q->fl_size = 1024;
- q->jumbo_size = 512;
+ q->jumbo_size = 512;
q->txq_size[TXQ_ETH] = 1024;
q->txq_size[TXQ_OFLD] = 1024;
q->txq_size[TXQ_CTRL] = 256;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
index 12fcf84d67ad..163efab27e9b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
@@ -106,8 +106,7 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
if (!list_empty(&ctbl->ce_free_head)) {
ce = list_first_entry(&ctbl->ce_free_head,
struct clip_entry, list);
- list_del(&ce->list);
- INIT_LIST_HEAD(&ce->list);
+ list_del_init(&ce->list);
spin_lock_init(&ce->lock);
refcount_set(&ce->refcnt, 0);
atomic_dec(&ctbl->nfree);
@@ -179,8 +178,7 @@ found:
write_lock_bh(&ctbl->lock);
spin_lock_bh(&ce->lock);
if (refcount_dec_and_test(&ce->refcnt)) {
- list_del(&ce->list);
- INIT_LIST_HEAD(&ce->list);
+ list_del_init(&ce->list);
list_add_tail(&ce->list, &ctbl->ce_free_head);
atomic_inc(&ctbl->nfree);
if (v6)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
index 70dbee89118e..5bf117d2179f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
@@ -446,7 +446,7 @@ void cxgb4_ptp_init(struct adapter *adapter)
}
/**
- * cxgb4_ptp_remove - disable PTP device and stop the overflow check
+ * cxgb4_ptp_stop - disable PTP device and stop the overflow check
* @adapter: board private structure
*
* Stop the PTP support.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 9428ef1f04a8..ae3ad99fbd06 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -6983,7 +6983,7 @@ int t4_fw_bye(struct adapter *adap, unsigned int mbox)
}
/**
- * t4_init_cmd - ask FW to initialize the device
+ * t4_early_init - ask FW to initialize the device
* @adap: the adapter
* @mbox: mailbox to use for the FW command
*
@@ -10224,7 +10224,7 @@ out:
}
/**
- * t4_set_vf_mac - Set MAC address for the specified VF
+ * t4_set_vf_mac_acl - Set MAC address for the specified VF
* @adapter: The adapter
* @vf: one of the VFs instantiated by the specified PF
* @naddr: the number of MAC addresses
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index 95657da0aa4b..7bc80eeb2c21 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -954,7 +954,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq,
}
/**
- * check_ring_tx_db - check and potentially ring a TX queue's doorbell
+ * ring_tx_db - check and potentially ring a TX queue's doorbell
* @adapter: the adapter
* @tq: the TX queue
* @n: number of new descriptors to give to HW
diff --git a/drivers/net/ethernet/dec/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c
index b018195f0243..117c26fa5909 100644
--- a/drivers/net/ethernet/dec/tulip/de2104x.c
+++ b/drivers/net/ethernet/dec/tulip/de2104x.c
@@ -832,8 +832,8 @@ static struct net_device_stats *de_get_stats(struct net_device *dev)
/* The chip only need report frame silently dropped. */
spin_lock_irq(&de->lock);
- if (netif_running(dev) && netif_device_present(dev))
- __de_get_stats(de);
+ if (netif_running(dev) && netif_device_present(dev))
+ __de_get_stats(de);
spin_unlock_irq(&de->lock);
return &dev->stats;
diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c
index 683e328b5461..b125d7faefdf 100644
--- a/drivers/net/ethernet/dec/tulip/de4x5.c
+++ b/drivers/net/ethernet/dec/tulip/de4x5.c
@@ -396,7 +396,7 @@
Updated the PCI interface to conform with the latest
version. I hope nothing is broken...
- Add TX done interrupt modification from suggestion
+ Add TX done interrupt modification from suggestion
Fix is_anc_capable() bug reported by
@@ -1499,7 +1499,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
netif_stop_queue(dev);
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
- lp->stats.tx_bytes += skb->len;
+ lp->stats.tx_bytes += skb->len;
outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
lp->tx_new = (lp->tx_new + 1) % lp->txRingSize;
@@ -1651,7 +1651,7 @@ de4x5_rx(struct net_device *dev)
/* Update stats */
lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ lp->stats.rx_bytes += pkt_len;
}
}
diff --git a/drivers/net/ethernet/dec/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c
index 87a27fe2992d..c763b692e164 100644
--- a/drivers/net/ethernet/dec/tulip/dmfe.c
+++ b/drivers/net/ethernet/dec/tulip/dmfe.c
@@ -518,7 +518,7 @@ static void dmfe_remove_one(struct pci_dev *pdev)
DMFE_DBUG(0, "dmfe_remove_one()", 0);
- if (dev) {
+ if (dev) {
unregister_netdev(dev);
pci_iounmap(db->pdev, db->ioaddr);
@@ -567,10 +567,10 @@ static int dmfe_open(struct net_device *dev)
/* CR6 operation mode decision */
if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||
(db->chip_revision >= 0x30) ) {
- db->cr6_data |= DMFE_TXTH_256;
+ db->cr6_data |= DMFE_TXTH_256;
db->cr0_data = CR0_DEFAULT;
db->dm910x_chk_mode=4; /* Enter the normal mode */
- } else {
+ } else {
db->cr6_data |= CR6_SFT; /* Store & Forward mode */
db->cr0_data = 0;
db->dm910x_chk_mode = 1; /* Enter the check mode */
@@ -903,7 +903,7 @@ static void dmfe_free_tx_pkt(struct net_device *dev, struct dmfe_board_info *db)
}
}
- txptr = txptr->next_tx_desc;
+ txptr = txptr->next_tx_desc;
}/* End of while */
/* Update TX remove pointer to next */
@@ -1121,7 +1121,7 @@ static void dmfe_timer(struct timer_list *t)
void __iomem *ioaddr = db->ioaddr;
u32 tmp_cr8;
unsigned char tmp_cr12;
- unsigned long flags;
+ unsigned long flags;
int link_ok, link_ok_phy;
@@ -1217,7 +1217,7 @@ static void dmfe_timer(struct timer_list *t)
if (link_ok_phy != link_ok) {
DMFE_DBUG (0, "PHY and chip report different link status", 0);
link_ok = link_ok | link_ok_phy;
- }
+ }
if ( !link_ok && netif_carrier_ok(dev)) {
/* Link Failed */
@@ -1699,14 +1699,14 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *db)
if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61;
}
- /* Write new capability to Phyxcer Reg4 */
+ /* Write new capability to Phyxcer Reg4 */
if ( !(phy_reg & 0x01e0)) {
phy_reg|=db->PHY_reg4;
db->media_mode|=DMFE_AUTO;
}
dmfe_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
- /* Restart Auto-Negotiation */
+ /* Restart Auto-Negotiation */
if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
if ( !db->chip_type )
@@ -1754,7 +1754,7 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
}
dmfe_phy_write(db->ioaddr,
db->phy_addr, 0, phy_reg, db->chip_id);
- if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
+ if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
mdelay(20);
dmfe_phy_write(db->ioaddr,
db->phy_addr, 0, phy_reg, db->chip_id);
diff --git a/drivers/net/ethernet/dec/tulip/pnic2.c b/drivers/net/ethernet/dec/tulip/pnic2.c
index 412adaa7fdf8..72a09156b48b 100644
--- a/drivers/net/ethernet/dec/tulip/pnic2.c
+++ b/drivers/net/ethernet/dec/tulip/pnic2.c
@@ -351,7 +351,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
del_timer_sync(&tp->timer);
pnic2_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
- add_timer(&tp->timer);
+ add_timer(&tp->timer);
}
return;
@@ -375,7 +375,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
del_timer_sync(&tp->timer);
pnic2_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
- add_timer(&tp->timer);
+ add_timer(&tp->timer);
}
return;
diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c
index 13e73ed15ef0..d67ef7d02d6b 100644
--- a/drivers/net/ethernet/dec/tulip/uli526x.c
+++ b/drivers/net/ethernet/dec/tulip/uli526x.c
@@ -780,7 +780,7 @@ static void uli526x_free_tx_pkt(struct net_device *dev,
}
}
- txptr = txptr->next_tx_desc;
+ txptr = txptr->next_tx_desc;
}/* End of while */
/* Update TX remove pointer to next */
@@ -1015,7 +1015,7 @@ static void uli526x_timer(struct timer_list *t)
struct net_device *dev = pci_get_drvdata(db->pdev);
struct uli_phy_ops *phy = &db->phy;
void __iomem *ioaddr = db->ioaddr;
- unsigned long flags;
+ unsigned long flags;
u8 tmp_cr12 = 0;
u32 tmp_cr8;
@@ -1535,14 +1535,14 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db)
}
- /* Write new capability to Phyxcer Reg4 */
+ /* Write new capability to Phyxcer Reg4 */
if ( !(phy_reg & 0x01e0)) {
phy_reg|=db->PHY_reg4;
db->media_mode|=ULI526X_AUTO;
}
phy->write(db, db->phy_addr, 4, phy_reg);
- /* Restart Auto-Negotiation */
+ /* Restart Auto-Negotiation */
phy->write(db, db->phy_addr, 0, 0x1200);
udelay(50);
}
@@ -1550,7 +1550,7 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db)
/*
* Process op-mode
- AUTO mode : PHY controller in Auto-negotiation Mode
+ AUTO mode : PHY controller in Auto-negotiation Mode
* Force mode: PHY controller in force mode with HUB
* N-way force capability with SWITCH
*/
diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c
index 514df170ec5d..f6ff1f76eacb 100644
--- a/drivers/net/ethernet/dec/tulip/winbond-840.c
+++ b/drivers/net/ethernet/dec/tulip/winbond-840.c
@@ -36,7 +36,7 @@
power management.
support for big endian descriptors
Copyright (C) 2001 Manfred Spraul
- * ethtool support (jgarzik)
+ * ethtool support (jgarzik)
* Replace some MII-related magic numbers with constants (jgarzik)
TODO:
@@ -1479,7 +1479,7 @@ static int netdev_close(struct net_device *dev)
np->cur_rx, np->dirty_rx);
}
- /* Stop the chip's Tx and Rx processes. */
+ /* Stop the chip's Tx and Rx processes. */
spin_lock_irq(&np->lock);
netif_device_detach(dev);
update_csr6(dev, 0);
diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c
index ce61f79f3b7c..ee0ca712dd1c 100644
--- a/drivers/net/ethernet/dlink/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -1847,20 +1847,20 @@ static int netdev_close(struct net_device *dev)
/* Stop the chip's Tx and Rx processes. */
iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
- for (i = 2000; i > 0; i--) {
- if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0)
+ for (i = 2000; i > 0; i--) {
+ if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0)
break;
mdelay(1);
- }
+ }
- iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset,
+ iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset,
ioaddr + ASIC_HI_WORD(ASICCtrl));
- for (i = 2000; i > 0; i--) {
+ for (i = 2000; i > 0; i--) {
if ((ioread16(ioaddr + ASIC_HI_WORD(ASICCtrl)) & ResetBusy) == 0)
break;
mdelay(1);
- }
+ }
#ifdef __i386__
if (netif_msg_hw(np)) {
diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c
index 0908771aa9ac..0f141c14d72d 100644
--- a/drivers/net/ethernet/fealnx.c
+++ b/drivers/net/ethernet/fealnx.c
@@ -144,7 +144,7 @@ struct chip_info {
};
static const struct chip_info skel_netdrv_tbl[] = {
- { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
+ { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
{ "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR },
{ "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
};
diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
index a7b7a4aace79..7e451e61eefd 100644
--- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -812,9 +812,9 @@ static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
if (length < ETH_ZLEN)
{
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
+ if (skb_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+ length = ETH_ZLEN;
}
netif_stop_queue(dev);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index c615fbf9094e..75e4ec569da8 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -462,8 +462,6 @@ static void hns_ae_adjust_link(struct hnae_handle *handle, int speed,
default:
break;
}
-
- return;
}
static void hns_ae_get_ring_bdnum_limit(struct hnae_queue *queue,
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index f4cf569a2599..f41379de2186 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -111,7 +111,7 @@ int hns_mac_get_port_info(struct hns_mac_cb *mac_cb,
}
/**
- *hns_mac_is_adjust_link - check is need change mac speed and duplex register
+ *hns_mac_need_adjust_link - check is need change mac speed and duplex register
*@mac_cb: mac device
*@speed: phy device speed
*@duplex:phy device duplex
@@ -374,7 +374,7 @@ static void hns_mac_param_get(struct mac_params *param,
}
/**
- * hns_mac_queue_config_bc_en - set broadcast rx&tx enable
+ * hns_mac_port_config_bc_en - set broadcast rx&tx enable
* @mac_cb: mac device
* @port_num: queue number
* @vlan_id: vlan id`
@@ -597,7 +597,7 @@ int hns_mac_set_autoneg(struct hns_mac_cb *mac_cb, u8 enable)
}
/**
- * hns_mac_set_autoneg - set rx & tx pause parameter
+ * hns_mac_set_pauseparam - set rx & tx pause parameter
* @mac_cb: mac control block
* @rx_en: rx enable or not
* @tx_en: tx enable or not
@@ -914,8 +914,7 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb)
}
} else if (is_acpi_node(mac_cb->fw_port)) {
ret = hns_mac_register_phy(mac_cb);
- /*
- * Mac can work well if there is phy or not.If the port don't
+ /* Mac can work well if there is phy or not.If the port don't
* connect with phy, the return value will be ignored. Only
* when there is phy but can't find mdio bus, the return value
* will be handled.
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
index c2a60612f503..fcaf5132b865 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
@@ -227,7 +227,7 @@ hns_dsaf_reg_cnt_clr_ce(struct dsaf_device *dsaf_dev, u32 reg_cnt_clr_ce)
}
/**
- * hns_ppe_qid_cfg - config ppe qid
+ * hns_dsaf_ppe_qid_cfg - config ppe qid
* @dsaf_dev: dsa fabric id
* @qid_cfg: value array
*/
@@ -613,7 +613,7 @@ static void hns_dsaf_tbl_tcam_data_cfg(
}
/**
- * dsaf_tbl_tcam_mcast_cfg - tbl
+ * hns_dsaf_tbl_tcam_mcast_cfg - tbl
* @dsaf_dev: dsa fabric id
* @mcast: addr
*/
@@ -1213,7 +1213,7 @@ void hns_dsaf_get_rx_mac_pause_en(struct dsaf_device *dsaf_dev, int mac_id,
}
/**
- * hns_dsaf_tbl_tcam_init - INT
+ * hns_dsaf_comm_init - INT
* @dsaf_dev: dsa fabric id
*/
static void hns_dsaf_comm_init(struct dsaf_device *dsaf_dev)
@@ -2111,7 +2111,7 @@ static void hns_dsaf_free_dev(struct dsaf_device *dsaf_dev)
}
/**
- * dsaf_pfc_unit_cnt - set pfc unit count
+ * hns_dsaf_pfc_unit_cnt - set pfc unit count
* @dsaf_dev: dsa fabric id
* @mac_id: id in use
* @rate: value array
@@ -2142,7 +2142,7 @@ static void hns_dsaf_pfc_unit_cnt(struct dsaf_device *dsaf_dev, int mac_id,
}
/**
- * dsaf_port_work_rate_cfg - fifo
+ * hns_dsaf_port_work_rate_cfg - fifo
* @dsaf_dev: dsa fabric id
* @mac_id: mac contrl block
* @rate_mode: value array
@@ -2738,7 +2738,7 @@ void hns_dsaf_get_strings(int stringset, u8 *data, int port,
}
/**
- *hns_dsaf_get_sset_count - get dsaf regs count
+ *hns_dsaf_get_regs_count - get dsaf regs count
*return dsaf regs count
*/
int hns_dsaf_get_regs_count(void)
@@ -2949,7 +2949,7 @@ int hns_dsaf_wait_pkt_clean(struct dsaf_device *dsaf_dev, int port)
}
/**
- * dsaf_probe - probo dsaf dev
+ * hns_dsaf_probe - probo dsaf dev
* @pdev: dasf platform device
* return 0 - success , negative --fail
*/
@@ -3004,7 +3004,7 @@ free_dev:
}
/**
- * dsaf_remove - remove dsaf dev
+ * hns_dsaf_remove - remove dsaf dev
* @pdev: dasf platform device
*/
static int hns_dsaf_remove(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
index 325e81d30cfd..23d9cbf262c3 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
@@ -56,31 +56,31 @@ static u32 dsaf_read_sub(struct dsaf_device *dsaf_dev, u32 reg)
}
static void hns_dsaf_acpi_ledctrl_by_port(struct hns_mac_cb *mac_cb, u8 op_type,
- u32 link, u32 port, u32 act)
+ u32 link, u32 port, u32 act)
{
- union acpi_object *obj;
- union acpi_object obj_args[3], argv4;
+ union acpi_object *obj;
+ union acpi_object obj_args[3], argv4;
- obj_args[0].integer.type = ACPI_TYPE_INTEGER;
- obj_args[0].integer.value = link;
- obj_args[1].integer.type = ACPI_TYPE_INTEGER;
- obj_args[1].integer.value = port;
- obj_args[2].integer.type = ACPI_TYPE_INTEGER;
- obj_args[2].integer.value = act;
+ obj_args[0].integer.type = ACPI_TYPE_INTEGER;
+ obj_args[0].integer.value = link;
+ obj_args[1].integer.type = ACPI_TYPE_INTEGER;
+ obj_args[1].integer.value = port;
+ obj_args[2].integer.type = ACPI_TYPE_INTEGER;
+ obj_args[2].integer.value = act;
- argv4.type = ACPI_TYPE_PACKAGE;
- argv4.package.count = 3;
- argv4.package.elements = obj_args;
+ argv4.type = ACPI_TYPE_PACKAGE;
+ argv4.package.count = 3;
+ argv4.package.elements = obj_args;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev),
- &hns_dsaf_acpi_dsm_guid, 0, op_type, &argv4);
- if (!obj) {
- dev_warn(mac_cb->dev, "ledctrl fail, link:%d port:%d act:%d!\n",
- link, port, act);
- return;
- }
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev),
+ &hns_dsaf_acpi_dsm_guid, 0, op_type, &argv4);
+ if (!obj) {
+ dev_warn(mac_cb->dev, "ledctrl fail, link:%d port:%d act:%d!\n",
+ link, port, act);
+ return;
+ }
- ACPI_FREE(obj);
+ ACPI_FREE(obj);
}
static void hns_dsaf_acpi_locate_ledctrl_by_port(struct hns_mac_cb *mac_cb,
@@ -151,15 +151,15 @@ static void hns_cpld_set_led(struct hns_mac_cb *mac_cb, int link_status,
}
static void hns_cpld_set_led_acpi(struct hns_mac_cb *mac_cb, int link_status,
- u16 speed, int data)
+ u16 speed, int data)
{
- if (!mac_cb) {
- pr_err("cpld_led_set mac_cb is null!\n");
- return;
- }
+ if (!mac_cb) {
+ pr_err("cpld_led_set mac_cb is null!\n");
+ return;
+ }
- hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
- link_status, mac_cb->mac_id, data);
+ hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
+ link_status, mac_cb->mac_id, data);
}
static void cpld_led_reset(struct hns_mac_cb *mac_cb)
@@ -174,16 +174,16 @@ static void cpld_led_reset(struct hns_mac_cb *mac_cb)
static void cpld_led_reset_acpi(struct hns_mac_cb *mac_cb)
{
- if (!mac_cb) {
- pr_err("cpld_led_reset mac_cb is null!\n");
- return;
- }
+ if (!mac_cb) {
+ pr_err("cpld_led_reset mac_cb is null!\n");
+ return;
+ }
- if (mac_cb->media_type != HNAE_MEDIA_TYPE_FIBER)
- return;
+ if (mac_cb->media_type != HNAE_MEDIA_TYPE_FIBER)
+ return;
- hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
- 0, mac_cb->mac_id, 0);
+ hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
+ 0, mac_cb->mac_id, 0);
}
static int cpld_set_led_id(struct hns_mac_cb *mac_cb,
@@ -351,7 +351,7 @@ hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool dereset)
}
/**
- * hns_dsaf_srst_chns - reset dsaf channels
+ * hns_dsaf_srst_chns_acpi - reset dsaf channels
* @dsaf_dev: dsaf device struct pointer
* @msk: xbar channels mask value:
* @dereset: false - request reset , true - drop reset
@@ -501,7 +501,7 @@ static void hns_ppe_com_srst(struct dsaf_device *dsaf_dev, bool dereset)
}
/**
- * hns_mac_get_sds_mode - get phy ifterface form serdes mode
+ * hns_mac_get_phy_if - get phy ifterface form serdes mode
* @mac_cb: mac control block
* retuen phy interface
*/
@@ -521,7 +521,7 @@ static phy_interface_t hns_mac_get_phy_if(struct hns_mac_cb *mac_cb)
reg = HNS_MAC_HILINK4_REG;
else
reg = HNS_MAC_HILINK3_REG;
- } else{
+ } else {
if (!HNS_DSAF_IS_DEBUG(mac_cb->dsaf_dev) && mac_id <= 3)
reg = HNS_MAC_HILINK4V2_REG;
else
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index ff03cafccb66..a7eb87da4e70 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -296,7 +296,7 @@ int hns_ppe_wait_tx_fifo_clean(struct hns_ppe_cb *ppe_cb)
}
/**
- * ppe_init_hw - init ppe
+ * hns_ppe_init_hw - init ppe
* @ppe_cb: ppe device
*/
static void hns_ppe_init_hw(struct hns_ppe_cb *ppe_cb)
@@ -343,7 +343,7 @@ static void hns_ppe_init_hw(struct hns_ppe_cb *ppe_cb)
}
/**
- * ppe_uninit_hw - uninit ppe
+ * hns_ppe_uninit_hw - uninit ppe
* @ppe_cb: ppe device
*/
static void hns_ppe_uninit_hw(struct hns_ppe_cb *ppe_cb)
@@ -382,7 +382,7 @@ void hns_ppe_uninit(struct dsaf_device *dsaf_dev)
}
/**
- * hns_ppe_reset - reinit ppe/rcb hw
+ * hns_ppe_reset_common - reinit ppe/rcb hw
* @dsaf_dev: dasf device
* @ppe_common_index: the index
* return void
@@ -455,7 +455,7 @@ int hns_ppe_get_regs_count(void)
}
/**
- * ppe_get_strings - get ppe srting
+ * hns_ppe_get_strings - get ppe srting
* @ppe_cb: ppe device
* @stringset: string set type
* @data: output string
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
index 5d5dc6942232..e2ff3ca198d1 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
@@ -913,7 +913,7 @@ int hns_rcb_get_common_regs_count(void)
}
/**
- *rcb_get_sset_count - rcb ring regs count
+ *hns_rcb_get_ring_regs_count - rcb ring regs count
*return regs count
*/
int hns_rcb_get_ring_regs_count(void)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
index be52acd448f9..401fef5f1d07 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
@@ -104,7 +104,7 @@ static void hns_xgmac_rx_enable(struct mac_driver *drv, u32 value)
}
/**
- * hns_xgmac_tx_lf_rf_insert - insert lf rf control about xgmac
+ * hns_xgmac_lf_rf_insert - insert lf rf control about xgmac
* @mac_drv: mac driver
* @mode: inserf rf or lf
*/
@@ -115,7 +115,7 @@ static void hns_xgmac_lf_rf_insert(struct mac_driver *mac_drv, u32 mode)
}
/**
- * hns_xgmac__lf_rf_control_init - initial the lf rf control register
+ * hns_xgmac_lf_rf_control_init - initial the lf rf control register
* @mac_drv: mac driver
*/
static void hns_xgmac_lf_rf_control_init(struct mac_driver *mac_drv)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index 5e349c0bdecc..ad534f9e41ab 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -770,7 +770,7 @@ static u32 smooth_alg(u32 new_param, u32 old_param)
}
/**
- * hns_nic_adp_coalesce - self adapte coalesce according to rx rate
+ * hns_nic_adpt_coalesce - self adapte coalesce according to rx rate
* @ring_data: pointer to hns_nic_ring_data
**/
static void hns_nic_adpt_coalesce(struct hns_nic_ring_data *ring_data)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index da48c05435ea..7e62dcff2426 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -192,7 +192,7 @@ static int hns_nic_get_link_ksettings(struct net_device *net_dev,
}
/**
- *hns_nic_set_link_settings - implement ethtool set link ksettings
+ *hns_nic_set_link_ksettings - implement ethtool set link ksettings
*@net_dev: net_device
*@cmd: ethtool_link_ksettings
*retuen 0 - success , negative --fail
@@ -827,7 +827,7 @@ hns_get_channels(struct net_device *net_dev, struct ethtool_channels *ch)
}
/**
- * get_ethtool_stats - get detail statistics.
+ * hns_get_ethtool_stats - get detail statistics.
* @netdev: net device
* @stats: statistics info.
* @data: statistics data.
@@ -885,7 +885,7 @@ static void hns_get_ethtool_stats(struct net_device *netdev,
}
/**
- * get_strings: Return a set of strings that describe the requested objects
+ * hns_get_strings: Return a set of strings that describe the requested objects
* @netdev: net device
* @stringset: string set ID.
* @data: objects data.
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 1d2189047781..d1cdb7494b9e 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -91,6 +91,7 @@ enum HNAE3_DEV_CAP_BITS {
HNAE3_DEV_SUPPORT_STASH_B,
HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B,
HNAE3_DEV_SUPPORT_PAUSE_B,
+ HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
};
#define hnae3_dev_fd_supported(hdev) \
@@ -141,6 +142,9 @@ enum HNAE3_DEV_CAP_BITS {
#define hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B, (ae_dev)->caps)
+#define hnae3_ae_dev_rxd_adv_layout_supported(ae_dev) \
+ test_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, (ae_dev)->caps)
+
#define ring_ptr_move_fw(ring, p) \
((ring)->p = ((ring)->p + 1) % (ring)->desc_num)
#define ring_ptr_move_bw(ring, p) \
@@ -246,6 +250,24 @@ enum hnae3_port_base_vlan_state {
HNAE3_PORT_BASE_VLAN_NOCHANGE,
};
+enum hnae3_dbg_cmd {
+ HNAE3_DBG_CMD_TM_NODES,
+ HNAE3_DBG_CMD_TM_PRI,
+ HNAE3_DBG_CMD_TM_QSET,
+ HNAE3_DBG_CMD_DEV_INFO,
+ HNAE3_DBG_CMD_TX_BD,
+ HNAE3_DBG_CMD_RX_BD,
+ HNAE3_DBG_CMD_MAC_UC,
+ HNAE3_DBG_CMD_MAC_MC,
+ HNAE3_DBG_CMD_MNG_TBL,
+ HNAE3_DBG_CMD_LOOPBACK,
+ HNAE3_DBG_CMD_INTERRUPT_INFO,
+ HNAE3_DBG_CMD_RESET_INFO,
+ HNAE3_DBG_CMD_IMP_INFO,
+ HNAE3_DBG_CMD_NCL_CONFIG,
+ HNAE3_DBG_CMD_UNKNOWN,
+};
+
struct hnae3_vector_info {
u8 __iomem *io_addr;
int vector;
@@ -623,7 +645,7 @@ struct hnae3_ae_ops {
int (*add_arfs_entry)(struct hnae3_handle *handle, u16 queue_id,
u16 flow_id, struct flow_keys *fkeys);
int (*dbg_run_cmd)(struct hnae3_handle *handle, const char *cmd_buf);
- int (*dbg_read_cmd)(struct hnae3_handle *handle, const char *cmd_buf,
+ int (*dbg_read_cmd)(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len);
pci_ers_result_t (*handle_hw_ras_error)(struct hnae3_ae_dev *ae_dev);
bool (*get_hw_reset_stat)(struct hnae3_handle *handle);
@@ -786,10 +808,6 @@ struct hnae3_handle {
#define hnae3_get_bit(origin, shift) \
hnae3_get_field(origin, 0x1 << (shift), shift)
-#define HNAE3_DBG_TM_NODES "tm_nodes"
-#define HNAE3_DBG_TM_PRI "tm_priority"
-#define HNAE3_DBG_TM_QSET "tm_qset"
-
int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev);
void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
index 9d702bd0c7c1..ba4ee8ca7e71 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
@@ -5,13 +5,193 @@
#include <linux/device.h>
#include "hnae3.h"
+#include "hns3_debugfs.h"
#include "hns3_enet.h"
-#define HNS3_DBG_READ_LEN 65536
-#define HNS3_DBG_WRITE_LEN 1024
-
static struct dentry *hns3_dbgfs_root;
+static struct hns3_dbg_dentry_info hns3_dbg_dentry[] = {
+ {
+ .name = "tm"
+ },
+ {
+ .name = "tx_bd_info"
+ },
+ {
+ .name = "rx_bd_info"
+ },
+ {
+ .name = "mac_list"
+ },
+ /* keep common at the bottom and add new directory above */
+ {
+ .name = "common"
+ },
+};
+
+static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, unsigned int cmd);
+static int hns3_dbg_common_file_init(struct hnae3_handle *handle,
+ unsigned int cmd);
+
+static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = {
+ {
+ .name = "tm_nodes",
+ .cmd = HNAE3_DBG_CMD_TM_NODES,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tm_priority",
+ .cmd = HNAE3_DBG_CMD_TM_PRI,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tm_qset",
+ .cmd = HNAE3_DBG_CMD_TM_QSET,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "dev_info",
+ .cmd = HNAE3_DBG_CMD_DEV_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tx_bd_queue",
+ .cmd = HNAE3_DBG_CMD_TX_BD,
+ .dentry = HNS3_DBG_DENTRY_TX_BD,
+ .buf_len = HNS3_DBG_READ_LEN_4MB,
+ .init = hns3_dbg_bd_file_init,
+ },
+ {
+ .name = "rx_bd_queue",
+ .cmd = HNAE3_DBG_CMD_RX_BD,
+ .dentry = HNS3_DBG_DENTRY_RX_BD,
+ .buf_len = HNS3_DBG_READ_LEN_4MB,
+ .init = hns3_dbg_bd_file_init,
+ },
+ {
+ .name = "uc",
+ .cmd = HNAE3_DBG_CMD_MAC_UC,
+ .dentry = HNS3_DBG_DENTRY_MAC,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "mc",
+ .cmd = HNAE3_DBG_CMD_MAC_MC,
+ .dentry = HNS3_DBG_DENTRY_MAC,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "mng_tbl",
+ .cmd = HNAE3_DBG_CMD_MNG_TBL,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "loopback",
+ .cmd = HNAE3_DBG_CMD_LOOPBACK,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "interrupt_info",
+ .cmd = HNAE3_DBG_CMD_INTERRUPT_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "reset_info",
+ .cmd = HNAE3_DBG_CMD_RESET_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "imp_info",
+ .cmd = HNAE3_DBG_CMD_IMP_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "ncl_config",
+ .cmd = HNAE3_DBG_CMD_NCL_CONFIG,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN_128KB,
+ .init = hns3_dbg_common_file_init,
+ },
+};
+
+static struct hns3_dbg_cap_info hns3_dbg_cap[] = {
+ {
+ .name = "support FD",
+ .cap_bit = HNAE3_DEV_SUPPORT_FD_B,
+ }, {
+ .name = "support GRO",
+ .cap_bit = HNAE3_DEV_SUPPORT_GRO_B,
+ }, {
+ .name = "support FEC",
+ .cap_bit = HNAE3_DEV_SUPPORT_FEC_B,
+ }, {
+ .name = "support UDP GSO",
+ .cap_bit = HNAE3_DEV_SUPPORT_UDP_GSO_B,
+ }, {
+ .name = "support PTP",
+ .cap_bit = HNAE3_DEV_SUPPORT_PTP_B,
+ }, {
+ .name = "support INT QL",
+ .cap_bit = HNAE3_DEV_SUPPORT_INT_QL_B,
+ }, {
+ .name = "support HW TX csum",
+ .cap_bit = HNAE3_DEV_SUPPORT_HW_TX_CSUM_B,
+ }, {
+ .name = "support UDP tunnel csum",
+ .cap_bit = HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B,
+ }, {
+ .name = "support TX push",
+ .cap_bit = HNAE3_DEV_SUPPORT_TX_PUSH_B,
+ }, {
+ .name = "support imp-controlled PHY",
+ .cap_bit = HNAE3_DEV_SUPPORT_PHY_IMP_B,
+ }, {
+ .name = "support rxd advanced layout",
+ .cap_bit = HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
+ },
+};
+
+static void hns3_dbg_fill_content(char *content, u16 len,
+ const struct hns3_dbg_item *items,
+ const char **result, u16 size)
+{
+ char *pos = content;
+ u16 i;
+
+ memset(content, ' ', len);
+ for (i = 0; i < size; i++) {
+ if (result)
+ strncpy(pos, result[i], strlen(result[i]));
+ else
+ strncpy(pos, items[i].name, strlen(items[i].name));
+
+ pos += strlen(items[i].name) + items[i].interval;
+ }
+
+ *pos++ = '\n';
+ *pos++ = '\0';
+}
+
static int hns3_dbg_queue_info(struct hnae3_handle *h,
const char *cmd_buf)
{
@@ -169,118 +349,159 @@ static int hns3_dbg_queue_map(struct hnae3_handle *h)
return 0;
}
-static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf)
+static const struct hns3_dbg_item rx_bd_info_items[] = {
+ { "BD_IDX", 3 },
+ { "L234_INFO", 2 },
+ { "PKT_LEN", 3 },
+ { "SIZE", 4 },
+ { "RSS_HASH", 4 },
+ { "FD_ID", 2 },
+ { "VLAN_TAG", 2 },
+ { "O_DM_VLAN_ID_FB", 2 },
+ { "OT_VLAN_TAG", 2 },
+ { "BD_BASE_INFO", 2 },
+ { "PTYPE", 2 },
+ { "HW_CSUM", 2 },
+};
+
+static void hns3_dump_rx_bd_info(struct hns3_nic_priv *priv,
+ struct hns3_desc *desc, char **result, int idx)
+{
+ unsigned int j = 0;
+
+ sprintf(result[j++], "%5d", idx);
+ sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.l234_info));
+ sprintf(result[j++], "%7u", le16_to_cpu(desc->rx.pkt_len));
+ sprintf(result[j++], "%4u", le16_to_cpu(desc->rx.size));
+ sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.rss_hash));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->rx.fd_id));
+ sprintf(result[j++], "%8u", le16_to_cpu(desc->rx.vlan_tag));
+ sprintf(result[j++], "%15u", le16_to_cpu(desc->rx.o_dm_vlan_id_fb));
+ sprintf(result[j++], "%11u", le16_to_cpu(desc->rx.ot_vlan_tag));
+ sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.bd_base_info));
+ if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) {
+ u32 ol_info = le32_to_cpu(desc->rx.ol_info);
+
+ sprintf(result[j++], "%5lu", hnae3_get_field(ol_info,
+ HNS3_RXD_PTYPE_M,
+ HNS3_RXD_PTYPE_S));
+ sprintf(result[j++], "%7u", le16_to_cpu(desc->csum));
+ } else {
+ sprintf(result[j++], "NA");
+ sprintf(result[j++], "NA");
+ }
+}
+
+static int hns3_dbg_rx_bd_info(struct hns3_dbg_data *d, char *buf, int len)
{
- struct hns3_nic_priv *priv = h->priv;
- struct hns3_desc *rx_desc, *tx_desc;
- struct device *dev = &h->pdev->dev;
+ char data_str[ARRAY_SIZE(rx_bd_info_items)][HNS3_DBG_DATA_STR_LEN];
+ struct hns3_nic_priv *priv = d->handle->priv;
+ char *result[ARRAY_SIZE(rx_bd_info_items)];
+ char content[HNS3_DBG_INFO_LEN];
struct hns3_enet_ring *ring;
- u32 tx_index, rx_index;
- u32 q_num, value;
- dma_addr_t addr;
- u16 mss_hw_csum;
- u32 l234info;
- int cnt;
+ struct hns3_desc *desc;
+ unsigned int i;
+ int pos = 0;
- cnt = sscanf(&cmd_buf[8], "%u %u", &q_num, &tx_index);
- if (cnt == 2) {
- rx_index = tx_index;
- } else if (cnt != 1) {
- dev_err(dev, "bd info: bad command string, cnt=%d\n", cnt);
+ if (d->qid >= d->handle->kinfo.num_tqps) {
+ dev_err(&d->handle->pdev->dev,
+ "queue%u is not in use\n", d->qid);
return -EINVAL;
}
- if (q_num >= h->kinfo.num_tqps) {
- dev_err(dev, "Queue number(%u) is out of range(0-%u)\n", q_num,
- h->kinfo.num_tqps - 1);
- return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(rx_bd_info_items); i++)
+ result[i] = &data_str[i][0];
+
+ pos += scnprintf(buf + pos, len - pos,
+ "Queue %u rx bd info:\n", d->qid);
+ hns3_dbg_fill_content(content, sizeof(content), rx_bd_info_items,
+ NULL, ARRAY_SIZE(rx_bd_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+
+ ring = &priv->ring[d->qid + d->handle->kinfo.num_tqps];
+ for (i = 0; i < ring->desc_num; i++) {
+ desc = &ring->desc[i];
+
+ hns3_dump_rx_bd_info(priv, desc, result, i);
+ hns3_dbg_fill_content(content, sizeof(content),
+ rx_bd_info_items, (const char **)result,
+ ARRAY_SIZE(rx_bd_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
}
- ring = &priv->ring[q_num];
- value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG);
- tx_index = (cnt == 1) ? value : tx_index;
+ return 0;
+}
+
+static const struct hns3_dbg_item tx_bd_info_items[] = {
+ { "BD_IDX", 5 },
+ { "ADDRESS", 2 },
+ { "VLAN_TAG", 2 },
+ { "SIZE", 2 },
+ { "T_CS_VLAN_TSO", 2 },
+ { "OT_VLAN_TAG", 3 },
+ { "TV", 2 },
+ { "OLT_VLAN_LEN", 2},
+ { "PAYLEN_OL4CS", 2},
+ { "BD_FE_SC_VLD", 2},
+ { "MSS_HW_CSUM", 0},
+};
+
+static void hns3_dump_tx_bd_info(struct hns3_nic_priv *priv,
+ struct hns3_desc *desc, char **result, int idx)
+{
+ unsigned int j = 0;
+
+ sprintf(result[j++], "%6d", idx);
+ sprintf(result[j++], "%#llx", le64_to_cpu(desc->addr));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.vlan_tag));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.send_size));
+ sprintf(result[j++], "%#x",
+ le32_to_cpu(desc->tx.type_cs_vlan_tso_len));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.outer_vlan_tag));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.tv));
+ sprintf(result[j++], "%10u",
+ le32_to_cpu(desc->tx.ol_type_vlan_len_msec));
+ sprintf(result[j++], "%#x", le32_to_cpu(desc->tx.paylen_ol4cs));
+ sprintf(result[j++], "%#x", le16_to_cpu(desc->tx.bdtp_fe_sc_vld_ra_ri));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.mss_hw_csum));
+}
+
+static int hns3_dbg_tx_bd_info(struct hns3_dbg_data *d, char *buf, int len)
+{
+ char data_str[ARRAY_SIZE(tx_bd_info_items)][HNS3_DBG_DATA_STR_LEN];
+ struct hns3_nic_priv *priv = d->handle->priv;
+ char *result[ARRAY_SIZE(tx_bd_info_items)];
+ char content[HNS3_DBG_INFO_LEN];
+ struct hns3_enet_ring *ring;
+ struct hns3_desc *desc;
+ unsigned int i;
+ int pos = 0;
- if (tx_index >= ring->desc_num) {
- dev_err(dev, "bd index(%u) is out of range(0-%u)\n", tx_index,
- ring->desc_num - 1);
+ if (d->qid >= d->handle->kinfo.num_tqps) {
+ dev_err(&d->handle->pdev->dev,
+ "queue%u is not in use\n", d->qid);
return -EINVAL;
}
- tx_desc = &ring->desc[tx_index];
- addr = le64_to_cpu(tx_desc->addr);
- mss_hw_csum = le16_to_cpu(tx_desc->tx.mss_hw_csum);
- dev_info(dev, "TX Queue Num: %u, BD Index: %u\n", q_num, tx_index);
- dev_info(dev, "(TX)addr: %pad\n", &addr);
- dev_info(dev, "(TX)vlan_tag: %u\n", le16_to_cpu(tx_desc->tx.vlan_tag));
- dev_info(dev, "(TX)send_size: %u\n",
- le16_to_cpu(tx_desc->tx.send_size));
-
- if (mss_hw_csum & BIT(HNS3_TXD_HW_CS_B)) {
- u32 offset = le32_to_cpu(tx_desc->tx.ol_type_vlan_len_msec);
- u32 start = le32_to_cpu(tx_desc->tx.type_cs_vlan_tso_len);
-
- dev_info(dev, "(TX)csum start: %u\n",
- hnae3_get_field(start,
- HNS3_TXD_CSUM_START_M,
- HNS3_TXD_CSUM_START_S));
- dev_info(dev, "(TX)csum offset: %u\n",
- hnae3_get_field(offset,
- HNS3_TXD_CSUM_OFFSET_M,
- HNS3_TXD_CSUM_OFFSET_S));
- } else {
- dev_info(dev, "(TX)vlan_tso: %u\n",
- tx_desc->tx.type_cs_vlan_tso);
- dev_info(dev, "(TX)l2_len: %u\n", tx_desc->tx.l2_len);
- dev_info(dev, "(TX)l3_len: %u\n", tx_desc->tx.l3_len);
- dev_info(dev, "(TX)l4_len: %u\n", tx_desc->tx.l4_len);
- dev_info(dev, "(TX)vlan_msec: %u\n",
- tx_desc->tx.ol_type_vlan_msec);
- dev_info(dev, "(TX)ol2_len: %u\n", tx_desc->tx.ol2_len);
- dev_info(dev, "(TX)ol3_len: %u\n", tx_desc->tx.ol3_len);
- dev_info(dev, "(TX)ol4_len: %u\n", tx_desc->tx.ol4_len);
- }
+ for (i = 0; i < ARRAY_SIZE(tx_bd_info_items); i++)
+ result[i] = &data_str[i][0];
- dev_info(dev, "(TX)vlan_tag: %u\n",
- le16_to_cpu(tx_desc->tx.outer_vlan_tag));
- dev_info(dev, "(TX)tv: %u\n", le16_to_cpu(tx_desc->tx.tv));
- dev_info(dev, "(TX)paylen_ol4cs: %u\n",
- le32_to_cpu(tx_desc->tx.paylen_ol4cs));
- dev_info(dev, "(TX)vld_ra_ri: %u\n",
- le16_to_cpu(tx_desc->tx.bdtp_fe_sc_vld_ra_ri));
- dev_info(dev, "(TX)mss_hw_csum: %u\n", mss_hw_csum);
-
- ring = &priv->ring[q_num + h->kinfo.num_tqps];
- value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG);
- rx_index = (cnt == 1) ? value : tx_index;
- rx_desc = &ring->desc[rx_index];
-
- addr = le64_to_cpu(rx_desc->addr);
- l234info = le32_to_cpu(rx_desc->rx.l234_info);
- dev_info(dev, "RX Queue Num: %u, BD Index: %u\n", q_num, rx_index);
- dev_info(dev, "(RX)addr: %pad\n", &addr);
- dev_info(dev, "(RX)l234_info: %u\n", l234info);
-
- if (l234info & BIT(HNS3_RXD_L2_CSUM_B)) {
- u32 lo, hi;
-
- lo = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_L_M,
- HNS3_RXD_L2_CSUM_L_S);
- hi = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_H_M,
- HNS3_RXD_L2_CSUM_H_S);
- dev_info(dev, "(RX)csum: %u\n", lo | hi << 8);
- }
+ pos += scnprintf(buf + pos, len - pos,
+ "Queue %u tx bd info:\n", d->qid);
+ hns3_dbg_fill_content(content, sizeof(content), tx_bd_info_items,
+ NULL, ARRAY_SIZE(tx_bd_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+
+ ring = &priv->ring[d->qid];
+ for (i = 0; i < ring->desc_num; i++) {
+ desc = &ring->desc[i];
- dev_info(dev, "(RX)pkt_len: %u\n", le16_to_cpu(rx_desc->rx.pkt_len));
- dev_info(dev, "(RX)size: %u\n", le16_to_cpu(rx_desc->rx.size));
- dev_info(dev, "(RX)rss_hash: %u\n", le32_to_cpu(rx_desc->rx.rss_hash));
- dev_info(dev, "(RX)fd_id: %u\n", le16_to_cpu(rx_desc->rx.fd_id));
- dev_info(dev, "(RX)vlan_tag: %u\n", le16_to_cpu(rx_desc->rx.vlan_tag));
- dev_info(dev, "(RX)o_dm_vlan_id_fb: %u\n",
- le16_to_cpu(rx_desc->rx.o_dm_vlan_id_fb));
- dev_info(dev, "(RX)ot_vlan_tag: %u\n",
- le16_to_cpu(rx_desc->rx.ot_vlan_tag));
- dev_info(dev, "(RX)bd_base_info: %u\n",
- le32_to_cpu(rx_desc->rx.bd_base_info));
+ hns3_dump_tx_bd_info(priv, desc, result, i);
+ hns3_dbg_fill_content(content, sizeof(content),
+ tx_bd_info_items, (const char **)result,
+ ARRAY_SIZE(tx_bd_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+ }
return 0;
}
@@ -294,9 +515,6 @@ static void hns3_dbg_help(struct hnae3_handle *h)
dev_info(&h->pdev->dev, "available commands\n");
dev_info(&h->pdev->dev, "queue info <number>\n");
dev_info(&h->pdev->dev, "queue map\n");
- dev_info(&h->pdev->dev, "bd info <q_num> <bd index>\n");
- dev_info(&h->pdev->dev, "dev capability\n");
- dev_info(&h->pdev->dev, "dev spec\n");
if (!hns3_is_phys_func(h->pdev))
return;
@@ -308,16 +526,8 @@ static void hns3_dbg_help(struct hnae3_handle *h)
dev_info(&h->pdev->dev, "dump qos pause cfg\n");
dev_info(&h->pdev->dev, "dump qos pri map\n");
dev_info(&h->pdev->dev, "dump qos buf cfg\n");
- dev_info(&h->pdev->dev, "dump mng tbl\n");
- dev_info(&h->pdev->dev, "dump reset info\n");
- dev_info(&h->pdev->dev, "dump m7 info\n");
- dev_info(&h->pdev->dev, "dump ncl_config <offset> <length>(in hex)\n");
dev_info(&h->pdev->dev, "dump mac tnl status\n");
- dev_info(&h->pdev->dev, "dump loopback\n");
dev_info(&h->pdev->dev, "dump qs shaper [qs id]\n");
- dev_info(&h->pdev->dev, "dump uc mac list <func id>\n");
- dev_info(&h->pdev->dev, "dump mc mac list <func id>\n");
- dev_info(&h->pdev->dev, "dump intr\n");
memset(printf_buf, 0, HNS3_DBG_BUF_LEN);
strncat(printf_buf, "dump reg [[bios common] [ssu <port_id>]",
@@ -338,65 +548,78 @@ static void hns3_dbg_help(struct hnae3_handle *h)
dev_info(&h->pdev->dev, "%s", printf_buf);
}
-static void hns3_dbg_dev_caps(struct hnae3_handle *h)
+static void
+hns3_dbg_dev_caps(struct hnae3_handle *h, char *buf, int len, int *pos)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
- unsigned long *caps;
-
- caps = ae_dev->caps;
-
- dev_info(&h->pdev->dev, "support FD: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_FD_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support GRO: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_GRO_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support FEC: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_FEC_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support UDP GSO: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_UDP_GSO_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support PTP: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_PTP_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support INT QL: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_INT_QL_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support HW TX csum: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support UDP tunnel csum: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, caps) ?
- "yes" : "no");
- dev_info(&h->pdev->dev, "support PAUSE: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps) ?
- "yes" : "no");
- dev_info(&h->pdev->dev, "support imp-controlled PHY: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, caps) ? "yes" : "no");
+ static const char * const str[] = {"no", "yes"};
+ unsigned long *caps = ae_dev->caps;
+ u32 i, state;
+
+ *pos += scnprintf(buf + *pos, len - *pos, "dev capability:\n");
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cap); i++) {
+ state = test_bit(hns3_dbg_cap[i].cap_bit, caps);
+ *pos += scnprintf(buf + *pos, len - *pos, "%s: %s\n",
+ hns3_dbg_cap[i].name, str[state]);
+ }
+
+ *pos += scnprintf(buf + *pos, len - *pos, "\n");
}
-static void hns3_dbg_dev_specs(struct hnae3_handle *h)
+static void
+hns3_dbg_dev_specs(struct hnae3_handle *h, char *buf, int len, int *pos)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
struct hnae3_dev_specs *dev_specs = &ae_dev->dev_specs;
struct hnae3_knic_private_info *kinfo = &h->kinfo;
- struct hns3_nic_priv *priv = h->priv;
-
- dev_info(priv->dev, "MAC entry num: %u\n", dev_specs->mac_entry_num);
- dev_info(priv->dev, "MNG entry num: %u\n", dev_specs->mng_entry_num);
- dev_info(priv->dev, "MAX non tso bd num: %u\n",
- dev_specs->max_non_tso_bd_num);
- dev_info(priv->dev, "RSS ind tbl size: %u\n",
- dev_specs->rss_ind_tbl_size);
- dev_info(priv->dev, "RSS key size: %u\n", dev_specs->rss_key_size);
- dev_info(priv->dev, "RSS size: %u\n", kinfo->rss_size);
- dev_info(priv->dev, "Allocated RSS size: %u\n", kinfo->req_rss_size);
- dev_info(priv->dev, "Task queue pairs numbers: %u\n", kinfo->num_tqps);
-
- dev_info(priv->dev, "RX buffer length: %u\n", kinfo->rx_buf_len);
- dev_info(priv->dev, "Desc num per TX queue: %u\n", kinfo->num_tx_desc);
- dev_info(priv->dev, "Desc num per RX queue: %u\n", kinfo->num_rx_desc);
- dev_info(priv->dev, "Total number of enabled TCs: %u\n",
- kinfo->tc_info.num_tc);
- dev_info(priv->dev, "MAX INT QL: %u\n", dev_specs->int_ql_max);
- dev_info(priv->dev, "MAX INT GL: %u\n", dev_specs->max_int_gl);
- dev_info(priv->dev, "MAX frame size: %u\n", dev_specs->max_frm_size);
- dev_info(priv->dev, "MAX TM RATE: %uMbps\n", dev_specs->max_tm_rate);
- dev_info(priv->dev, "MAX QSET number: %u\n", dev_specs->max_qset_num);
+
+ *pos += scnprintf(buf + *pos, len - *pos, "dev_spec:\n");
+ *pos += scnprintf(buf + *pos, len - *pos, "MAC entry num: %u\n",
+ dev_specs->mac_entry_num);
+ *pos += scnprintf(buf + *pos, len - *pos, "MNG entry num: %u\n",
+ dev_specs->mng_entry_num);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX non tso bd num: %u\n",
+ dev_specs->max_non_tso_bd_num);
+ *pos += scnprintf(buf + *pos, len - *pos, "RSS ind tbl size: %u\n",
+ dev_specs->rss_ind_tbl_size);
+ *pos += scnprintf(buf + *pos, len - *pos, "RSS key size: %u\n",
+ dev_specs->rss_key_size);
+ *pos += scnprintf(buf + *pos, len - *pos, "RSS size: %u\n",
+ kinfo->rss_size);
+ *pos += scnprintf(buf + *pos, len - *pos, "Allocated RSS size: %u\n",
+ kinfo->req_rss_size);
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "Task queue pairs numbers: %u\n",
+ kinfo->num_tqps);
+ *pos += scnprintf(buf + *pos, len - *pos, "RX buffer length: %u\n",
+ kinfo->rx_buf_len);
+ *pos += scnprintf(buf + *pos, len - *pos, "Desc num per TX queue: %u\n",
+ kinfo->num_tx_desc);
+ *pos += scnprintf(buf + *pos, len - *pos, "Desc num per RX queue: %u\n",
+ kinfo->num_rx_desc);
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "Total number of enabled TCs: %u\n",
+ kinfo->tc_info.num_tc);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX INT QL: %u\n",
+ dev_specs->int_ql_max);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX INT GL: %u\n",
+ dev_specs->max_int_gl);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX TM RATE: %u\n",
+ dev_specs->max_tm_rate);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX QSET number: %u\n",
+ dev_specs->max_qset_num);
+}
+
+static int hns3_dbg_dev_info(struct hnae3_handle *h, char *buf, int len)
+{
+ int pos = 0;
+
+ hns3_dbg_dev_caps(h, buf, len, &pos);
+
+ hns3_dbg_dev_specs(h, buf, len, &pos);
+
+ return 0;
}
static ssize_t hns3_dbg_cmd_read(struct file *filp, char __user *buffer,
@@ -438,12 +661,6 @@ static int hns3_dbg_check_cmd(struct hnae3_handle *handle, char *cmd_buf)
ret = hns3_dbg_queue_info(handle, cmd_buf);
else if (strncmp(cmd_buf, "queue map", 9) == 0)
ret = hns3_dbg_queue_map(handle);
- else if (strncmp(cmd_buf, "bd info", 7) == 0)
- ret = hns3_dbg_bd_info(handle, cmd_buf);
- else if (strncmp(cmd_buf, "dev capability", 14) == 0)
- hns3_dbg_dev_caps(handle);
- else if (strncmp(cmd_buf, "dev spec", 8) == 0)
- hns3_dbg_dev_specs(handle);
else if (handle->ae_algo->ops->dbg_run_cmd)
ret = handle->ae_algo->ops->dbg_run_cmd(handle, cmd_buf);
else
@@ -500,37 +717,120 @@ static ssize_t hns3_dbg_cmd_write(struct file *filp, const char __user *buffer,
return count;
}
+static int hns3_dbg_get_cmd_index(struct hnae3_handle *handle,
+ const unsigned char *name, u32 *index)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
+ if (!strncmp(name, hns3_dbg_cmd[i].name,
+ strlen(hns3_dbg_cmd[i].name))) {
+ *index = i;
+ return 0;
+ }
+ }
+
+ dev_err(&handle->pdev->dev, "unknown command(%s)\n", name);
+ return -EINVAL;
+}
+
+static const struct hns3_dbg_func hns3_dbg_cmd_func[] = {
+ {
+ .cmd = HNAE3_DBG_CMD_DEV_INFO,
+ .dbg_dump = hns3_dbg_dev_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TX_BD,
+ .dbg_dump_bd = hns3_dbg_tx_bd_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_RX_BD,
+ .dbg_dump_bd = hns3_dbg_rx_bd_info,
+ },
+};
+
+static int hns3_dbg_read_cmd(struct hns3_dbg_data *dbg_data,
+ enum hnae3_dbg_cmd cmd, char *buf, int len)
+{
+ const struct hnae3_ae_ops *ops = dbg_data->handle->ae_algo->ops;
+ const struct hns3_dbg_func *cmd_func;
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd_func); i++) {
+ if (cmd == hns3_dbg_cmd_func[i].cmd) {
+ cmd_func = &hns3_dbg_cmd_func[i];
+ if (cmd_func->dbg_dump)
+ return cmd_func->dbg_dump(dbg_data->handle, buf,
+ len);
+ else
+ return cmd_func->dbg_dump_bd(dbg_data, buf,
+ len);
+ }
+ }
+
+ if (!ops->dbg_read_cmd)
+ return -EOPNOTSUPP;
+
+ return ops->dbg_read_cmd(dbg_data->handle, cmd, buf, len);
+}
+
static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
- struct hnae3_handle *handle = filp->private_data;
- const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
+ struct hns3_dbg_data *dbg_data = filp->private_data;
+ struct hnae3_handle *handle = dbg_data->handle;
struct hns3_nic_priv *priv = handle->priv;
- char *cmd_buf, *read_buf;
ssize_t size = 0;
- int ret = 0;
-
- read_buf = kzalloc(HNS3_DBG_READ_LEN, GFP_KERNEL);
- if (!read_buf)
- return -ENOMEM;
+ char **save_buf;
+ char *read_buf;
+ u32 index;
+ int ret;
- cmd_buf = filp->f_path.dentry->d_iname;
+ ret = hns3_dbg_get_cmd_index(handle, filp->f_path.dentry->d_iname,
+ &index);
+ if (ret)
+ return ret;
- if (ops->dbg_read_cmd)
- ret = ops->dbg_read_cmd(handle, cmd_buf, read_buf,
- HNS3_DBG_READ_LEN);
+ save_buf = &hns3_dbg_cmd[index].buf;
- if (ret) {
- dev_info(priv->dev, "unknown command\n");
+ if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
+ test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) {
+ ret = -EBUSY;
goto out;
}
+ if (*save_buf) {
+ read_buf = *save_buf;
+ } else {
+ read_buf = kvzalloc(hns3_dbg_cmd[index].buf_len, GFP_KERNEL);
+ if (!read_buf)
+ return -ENOMEM;
+
+ /* save the buffer addr until the last read operation */
+ *save_buf = read_buf;
+ }
+
+ /* get data ready for the first time to read */
+ if (!*ppos) {
+ ret = hns3_dbg_read_cmd(dbg_data, hns3_dbg_cmd[index].cmd,
+ read_buf, hns3_dbg_cmd[index].buf_len);
+ if (ret)
+ goto out;
+ }
+
size = simple_read_from_buffer(buffer, count, ppos, read_buf,
strlen(read_buf));
+ if (size > 0)
+ return size;
out:
- kfree(read_buf);
- return size;
+ /* free the buffer for the last read operation */
+ if (*save_buf) {
+ kvfree(*save_buf);
+ *save_buf = NULL;
+ }
+
+ return ret;
}
static const struct file_operations hns3_dbg_cmd_fops = {
@@ -546,29 +846,109 @@ static const struct file_operations hns3_dbg_fops = {
.read = hns3_dbg_read,
};
-void hns3_dbg_init(struct hnae3_handle *handle)
+static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, u32 cmd)
+{
+ struct dentry *entry_dir;
+ struct hns3_dbg_data *data;
+ u16 max_queue_num;
+ unsigned int i;
+
+ entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry;
+ max_queue_num = hns3_get_max_available_channels(handle);
+ data = devm_kzalloc(&handle->pdev->dev, max_queue_num * sizeof(*data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ for (i = 0; i < max_queue_num; i++) {
+ char name[HNS3_DBG_FILE_NAME_LEN];
+
+ data[i].handle = handle;
+ data[i].qid = i;
+ sprintf(name, "%s%u", hns3_dbg_cmd[cmd].name, i);
+ debugfs_create_file(name, 0400, entry_dir, &data[i],
+ &hns3_dbg_fops);
+ }
+
+ return 0;
+}
+
+static int
+hns3_dbg_common_file_init(struct hnae3_handle *handle, u32 cmd)
+{
+ struct hns3_dbg_data *data;
+ struct dentry *entry_dir;
+
+ data = devm_kzalloc(&handle->pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->handle = handle;
+ entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry;
+ debugfs_create_file(hns3_dbg_cmd[cmd].name, 0400, entry_dir,
+ data, &hns3_dbg_fops);
+
+ return 0;
+}
+
+int hns3_dbg_init(struct hnae3_handle *handle)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
const char *name = pci_name(handle->pdev);
- struct dentry *entry_dir;
+ int ret;
+ u32 i;
- handle->hnae3_dbgfs = debugfs_create_dir(name, hns3_dbgfs_root);
+ hns3_dbg_dentry[HNS3_DBG_DENTRY_COMMON].dentry =
+ debugfs_create_dir(name, hns3_dbgfs_root);
+ handle->hnae3_dbgfs = hns3_dbg_dentry[HNS3_DBG_DENTRY_COMMON].dentry;
debugfs_create_file("cmd", 0600, handle->hnae3_dbgfs, handle,
&hns3_dbg_cmd_fops);
- entry_dir = debugfs_create_dir("tm", handle->hnae3_dbgfs);
- if (ae_dev->dev_version > HNAE3_DEVICE_VERSION_V2)
- debugfs_create_file(HNAE3_DBG_TM_NODES, 0600, entry_dir, handle,
- &hns3_dbg_fops);
- debugfs_create_file(HNAE3_DBG_TM_PRI, 0600, entry_dir, handle,
- &hns3_dbg_fops);
- debugfs_create_file(HNAE3_DBG_TM_QSET, 0600, entry_dir, handle,
- &hns3_dbg_fops);
+ for (i = 0; i < HNS3_DBG_DENTRY_COMMON; i++)
+ hns3_dbg_dentry[i].dentry =
+ debugfs_create_dir(hns3_dbg_dentry[i].name,
+ handle->hnae3_dbgfs);
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
+ if (hns3_dbg_cmd[i].cmd == HNAE3_DBG_CMD_TM_NODES &&
+ ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2)
+ continue;
+
+ if (!hns3_dbg_cmd[i].init) {
+ dev_err(&handle->pdev->dev,
+ "cmd %s lack of init func\n",
+ hns3_dbg_cmd[i].name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = hns3_dbg_cmd[i].init(handle, i);
+ if (ret) {
+ dev_err(&handle->pdev->dev, "failed to init cmd %s\n",
+ hns3_dbg_cmd[i].name);
+ goto out;
+ }
+ }
+
+ return 0;
+
+out:
+ debugfs_remove_recursive(handle->hnae3_dbgfs);
+ handle->hnae3_dbgfs = NULL;
+ return ret;
}
void hns3_dbg_uninit(struct hnae3_handle *handle)
{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++)
+ if (hns3_dbg_cmd[i].buf) {
+ kvfree(hns3_dbg_cmd[i].buf);
+ hns3_dbg_cmd[i].buf = NULL;
+ }
+
debugfs_remove_recursive(handle->hnae3_dbgfs);
handle->hnae3_dbgfs = NULL;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h
new file mode 100644
index 000000000000..a7af9277ae69
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2021 Hisilicon Limited. */
+
+#ifndef __HNS3_DEBUGFS_H
+#define __HNS3_DEBUGFS_H
+
+#define HNS3_DBG_READ_LEN 65536
+#define HNS3_DBG_READ_LEN_128KB 0x20000
+#define HNS3_DBG_READ_LEN_4MB 0x400000
+#define HNS3_DBG_WRITE_LEN 1024
+
+#define HNS3_DBG_DATA_STR_LEN 32
+#define HNS3_DBG_INFO_LEN 256
+#define HNS3_DBG_ITEM_NAME_LEN 32
+#define HNS3_DBG_FILE_NAME_LEN 16
+
+struct hns3_dbg_item {
+ char name[HNS3_DBG_ITEM_NAME_LEN];
+ u16 interval; /* blank numbers after the item */
+};
+
+struct hns3_dbg_data {
+ struct hnae3_handle *handle;
+ u16 qid;
+};
+
+enum hns3_dbg_dentry_type {
+ HNS3_DBG_DENTRY_TM,
+ HNS3_DBG_DENTRY_TX_BD,
+ HNS3_DBG_DENTRY_RX_BD,
+ HNS3_DBG_DENTRY_MAC,
+ HNS3_DBG_DENTRY_COMMON,
+};
+
+struct hns3_dbg_dentry_info {
+ const char *name;
+ struct dentry *dentry;
+};
+
+struct hns3_dbg_cmd_info {
+ const char *name;
+ enum hnae3_dbg_cmd cmd;
+ enum hns3_dbg_dentry_type dentry;
+ u32 buf_len;
+ char *buf;
+ int (*init)(struct hnae3_handle *handle, unsigned int cmd);
+};
+
+struct hns3_dbg_func {
+ enum hnae3_dbg_cmd cmd;
+ int (*dbg_dump)(struct hnae3_handle *handle, char *buf, int len);
+ int (*dbg_dump_bd)(struct hns3_dbg_data *data, char *buf, int len);
+};
+
+struct hns3_dbg_cap_info {
+ const char *name;
+ enum HNAE3_DEV_CAP_BITS cap_bit;
+};
+
+#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 783fdaf8f8d6..de0e2d215879 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -91,6 +91,278 @@ static const struct pci_device_id hns3_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, hns3_pci_tbl);
+#define HNS3_RX_PTYPE_ENTRY(ptype, l, s, t) \
+ { ptype, \
+ l, \
+ CHECKSUM_##s, \
+ HNS3_L3_TYPE_##t, \
+ 1 }
+
+#define HNS3_RX_PTYPE_UNUSED_ENTRY(ptype) \
+ { ptype, 0, CHECKSUM_NONE, HNS3_L3_TYPE_PARSE_FAIL, 0 }
+
+static const struct hns3_rx_ptype hns3_rx_ptype_tbl[] = {
+ HNS3_RX_PTYPE_UNUSED_ENTRY(0),
+ HNS3_RX_PTYPE_ENTRY(1, 0, COMPLETE, ARP),
+ HNS3_RX_PTYPE_ENTRY(2, 0, COMPLETE, RARP),
+ HNS3_RX_PTYPE_ENTRY(3, 0, COMPLETE, LLDP),
+ HNS3_RX_PTYPE_ENTRY(4, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(5, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(6, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(7, 0, COMPLETE, CNM),
+ HNS3_RX_PTYPE_ENTRY(8, 0, NONE, PARSE_FAIL),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(9),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(10),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(11),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(12),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(13),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(14),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(15),
+ HNS3_RX_PTYPE_ENTRY(16, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(17, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(18, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(19, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(20, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(21, 0, NONE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(22, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(23, 0, NONE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(24, 0, NONE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(25, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(26),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(27),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(28),
+ HNS3_RX_PTYPE_ENTRY(29, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(30, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(31, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(32, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(33, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(34, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(35, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(36, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(37, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(38),
+ HNS3_RX_PTYPE_ENTRY(39, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(40, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(41, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(42, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(43, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(44, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(45, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(46),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(47),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(48),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(49),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(50),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(51),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(52),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(53),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(54),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(55),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(56),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(57),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(58),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(59),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(60),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(61),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(62),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(63),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(64),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(65),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(66),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(67),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(68),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(69),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(70),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(71),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(72),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(73),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(74),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(75),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(76),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(77),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(78),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(79),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(80),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(81),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(82),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(83),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(84),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(85),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(86),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(87),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(88),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(89),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(90),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(91),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(92),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(93),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(94),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(95),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(96),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(97),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(98),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(99),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(100),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(101),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(102),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(103),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(104),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(105),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(106),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(107),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(108),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(109),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(110),
+ HNS3_RX_PTYPE_ENTRY(111, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(112, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(113, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(114, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(115, 0, NONE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(116, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(117, 0, NONE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(118, 0, NONE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(119, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(120),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(121),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(122),
+ HNS3_RX_PTYPE_ENTRY(123, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(124, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(125, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(126, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(127, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(128, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(129, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(130, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(131, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(132),
+ HNS3_RX_PTYPE_ENTRY(133, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(134, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(135, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(136, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(137, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(138, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(139, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(140),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(141),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(142),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(143),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(144),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(145),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(146),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(147),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(148),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(149),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(150),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(151),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(152),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(153),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(154),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(155),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(156),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(157),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(158),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(159),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(160),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(161),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(162),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(163),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(164),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(165),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(166),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(167),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(168),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(169),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(170),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(171),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(172),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(173),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(174),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(175),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(176),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(177),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(178),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(179),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(180),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(181),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(182),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(183),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(184),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(185),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(186),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(187),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(188),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(189),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(190),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(191),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(192),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(193),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(194),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(195),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(196),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(197),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(198),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(199),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(200),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(201),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(202),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(203),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(204),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(205),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(206),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(207),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(208),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(209),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(210),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(211),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(212),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(213),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(214),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(215),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(216),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(217),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(218),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(219),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(220),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(221),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(222),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(223),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(224),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(225),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(226),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(227),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(228),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(229),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(230),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(231),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(232),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(233),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(234),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(235),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(236),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(237),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(238),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(239),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(240),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(241),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(242),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(243),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(244),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(245),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(246),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(247),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(248),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(249),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(250),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(251),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(252),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(253),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(254),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(255),
+};
+
+#define HNS3_INVALID_PTYPE \
+ ARRAY_SIZE(hns3_rx_ptype_tbl)
+
static irqreturn_t hns3_irq_handle(int irq, void *vector)
{
struct hns3_enet_tqp_vector *tqp_vector = vector;
@@ -362,7 +634,7 @@ static int hns3_nic_set_real_num_queue(struct net_device *netdev)
return 0;
}
-static u16 hns3_get_max_available_channels(struct hnae3_handle *h)
+u16 hns3_get_max_available_channels(struct hnae3_handle *h)
{
u16 alloc_tqps, max_rss_size, rss_size;
@@ -2980,51 +3252,31 @@ static int hns3_gro_complete(struct sk_buff *skb, u32 l234info)
return 0;
}
-static void hns3_checksum_complete(struct hns3_enet_ring *ring,
- struct sk_buff *skb, u32 l234info)
+static bool hns3_checksum_complete(struct hns3_enet_ring *ring,
+ struct sk_buff *skb, u32 ptype, u16 csum)
{
- u32 lo, hi;
+ if (ptype == HNS3_INVALID_PTYPE ||
+ hns3_rx_ptype_tbl[ptype].ip_summed != CHECKSUM_COMPLETE)
+ return false;
u64_stats_update_begin(&ring->syncp);
ring->stats.csum_complete++;
u64_stats_update_end(&ring->syncp);
skb->ip_summed = CHECKSUM_COMPLETE;
- lo = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_L_M,
- HNS3_RXD_L2_CSUM_L_S);
- hi = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_H_M,
- HNS3_RXD_L2_CSUM_H_S);
- skb->csum = csum_unfold((__force __sum16)(lo | hi << 8));
+ skb->csum = csum_unfold((__force __sum16)csum);
+
+ return true;
}
-static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
- u32 l234info, u32 bd_base_info, u32 ol_info)
+static void hns3_rx_handle_csum(struct sk_buff *skb, u32 l234info,
+ u32 ol_info, u32 ptype)
{
- struct net_device *netdev = ring_to_netdev(ring);
int l3_type, l4_type;
int ol4_type;
- skb->ip_summed = CHECKSUM_NONE;
-
- skb_checksum_none_assert(skb);
-
- if (!(netdev->features & NETIF_F_RXCSUM))
- return;
-
- if (l234info & BIT(HNS3_RXD_L2_CSUM_B)) {
- hns3_checksum_complete(ring, skb, l234info);
- return;
- }
-
- /* check if hardware has done checksum */
- if (!(bd_base_info & BIT(HNS3_RXD_L3L4P_B)))
- return;
-
- if (unlikely(l234info & (BIT(HNS3_RXD_L3E_B) | BIT(HNS3_RXD_L4E_B) |
- BIT(HNS3_RXD_OL3E_B) |
- BIT(HNS3_RXD_OL4E_B)))) {
- u64_stats_update_begin(&ring->syncp);
- ring->stats.l3l4_csum_err++;
- u64_stats_update_end(&ring->syncp);
+ if (ptype != HNS3_INVALID_PTYPE) {
+ skb->csum_level = hns3_rx_ptype_tbl[ptype].csum_level;
+ skb->ip_summed = hns3_rx_ptype_tbl[ptype].ip_summed;
return;
}
@@ -3054,6 +3306,45 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
}
}
+static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
+ u32 l234info, u32 bd_base_info, u32 ol_info,
+ u16 csum)
+{
+ struct net_device *netdev = ring_to_netdev(ring);
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ u32 ptype = HNS3_INVALID_PTYPE;
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ skb_checksum_none_assert(skb);
+
+ if (!(netdev->features & NETIF_F_RXCSUM))
+ return;
+
+ if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state))
+ ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M,
+ HNS3_RXD_PTYPE_S);
+
+ if (hns3_checksum_complete(ring, skb, ptype, csum))
+ return;
+
+ /* check if hardware has done checksum */
+ if (!(bd_base_info & BIT(HNS3_RXD_L3L4P_B)))
+ return;
+
+ if (unlikely(l234info & (BIT(HNS3_RXD_L3E_B) | BIT(HNS3_RXD_L4E_B) |
+ BIT(HNS3_RXD_OL3E_B) |
+ BIT(HNS3_RXD_OL4E_B)))) {
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.l3l4_csum_err++;
+ u64_stats_update_end(&ring->syncp);
+
+ return;
+ }
+
+ hns3_rx_handle_csum(skb, l234info, ol_info, ptype);
+}
+
static void hns3_rx_skb(struct hns3_enet_ring *ring, struct sk_buff *skb)
{
if (skb_has_frag_list(skb))
@@ -3235,8 +3526,10 @@ static int hns3_add_frag(struct hns3_enet_ring *ring)
static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
struct sk_buff *skb, u32 l234info,
- u32 bd_base_info, u32 ol_info)
+ u32 bd_base_info, u32 ol_info, u16 csum)
{
+ struct net_device *netdev = ring_to_netdev(ring);
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
u32 l3_type;
skb_shinfo(skb)->gso_size = hnae3_get_field(bd_base_info,
@@ -3244,7 +3537,8 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
HNS3_RXD_GRO_SIZE_S);
/* if there is no HW GRO, do not set gro params */
if (!skb_shinfo(skb)->gso_size) {
- hns3_rx_checksum(ring, skb, l234info, bd_base_info, ol_info);
+ hns3_rx_checksum(ring, skb, l234info, bd_base_info, ol_info,
+ csum);
return 0;
}
@@ -3252,7 +3546,16 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
HNS3_RXD_GRO_COUNT_M,
HNS3_RXD_GRO_COUNT_S);
- l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M, HNS3_RXD_L3ID_S);
+ if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) {
+ u32 ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M,
+ HNS3_RXD_PTYPE_S);
+
+ l3_type = hns3_rx_ptype_tbl[ptype].l3_type;
+ } else {
+ l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M,
+ HNS3_RXD_L3ID_S);
+ }
+
if (l3_type == HNS3_L3_TYPE_IPV4)
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
else if (l3_type == HNS3_L3_TYPE_IPV6)
@@ -3285,6 +3588,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
struct hns3_desc *desc;
unsigned int len;
int pre_ntc, ret;
+ u16 csum;
/* bdinfo handled below is only valid on the last BD of the
* current packet, and ring->next_to_clean indicates the first
@@ -3296,6 +3600,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
bd_base_info = le32_to_cpu(desc->rx.bd_base_info);
l234info = le32_to_cpu(desc->rx.l234_info);
ol_info = le32_to_cpu(desc->rx.ol_info);
+ csum = le16_to_cpu(desc->csum);
/* Based on hw strategy, the tag offloaded will be stored at
* ot_vlan_tag in two layer tag case, and stored at vlan_tag
@@ -3328,7 +3633,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
/* This is needed in order to enable forwarding support */
ret = hns3_set_gro_and_checksum(ring, skb, l234info,
- bd_base_info, ol_info);
+ bd_base_info, ol_info, csum);
if (unlikely(ret)) {
u64_stats_update_begin(&ring->syncp);
ring->stats.rx_err_cnt++;
@@ -4343,13 +4648,21 @@ static int hns3_client_init(struct hnae3_handle *handle)
hns3_dcbnl_setup(handle);
- hns3_dbg_init(handle);
+ ret = hns3_dbg_init(handle);
+ if (ret) {
+ dev_err(priv->dev, "failed to init debugfs, ret = %d\n",
+ ret);
+ goto out_client_start;
+ }
netdev->max_mtu = HNS3_MAX_MTU(ae_dev->dev_specs.max_frm_size);
if (test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps))
set_bit(HNS3_NIC_STATE_HW_TX_CSUM_ENABLE, &priv->state);
+ if (hnae3_ae_dev_rxd_adv_layout_supported(ae_dev))
+ set_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state);
+
set_bit(HNS3_NIC_STATE_INITED, &priv->state);
if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
index daa04aeb0942..79ff2fa61d47 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
@@ -19,6 +19,7 @@ enum hns3_nic_state {
HNS3_NIC_STATE_SERVICE_SCHED,
HNS3_NIC_STATE2_RESET_REQUESTED,
HNS3_NIC_STATE_HW_TX_CSUM_ENABLE,
+ HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE,
HNS3_NIC_STATE_MAX
};
@@ -82,12 +83,6 @@ enum hns3_nic_state {
#define HNS3_RXD_STRP_TAGP_S 13
#define HNS3_RXD_STRP_TAGP_M (0x3 << HNS3_RXD_STRP_TAGP_S)
-#define HNS3_RXD_L2_CSUM_B 15
-#define HNS3_RXD_L2_CSUM_L_S 4
-#define HNS3_RXD_L2_CSUM_L_M (0xff << HNS3_RXD_L2_CSUM_L_S)
-#define HNS3_RXD_L2_CSUM_H_S 24
-#define HNS3_RXD_L2_CSUM_H_M (0xff << HNS3_RXD_L2_CSUM_H_S)
-
#define HNS3_RXD_L2E_B 16
#define HNS3_RXD_L3E_B 17
#define HNS3_RXD_L4E_B 18
@@ -114,6 +109,9 @@ enum hns3_nic_state {
#define HNS3_RXD_FBLI_S 14
#define HNS3_RXD_FBLI_M (0x3 << HNS3_RXD_FBLI_S)
+#define HNS3_RXD_PTYPE_S 4
+#define HNS3_RXD_PTYPE_M GENMASK(11, 4)
+
#define HNS3_RXD_BDTYPE_S 0
#define HNS3_RXD_BDTYPE_M (0xf << HNS3_RXD_BDTYPE_S)
#define HNS3_RXD_VLD_B 4
@@ -238,7 +236,10 @@ enum hns3_pkt_tun_type {
/* hardware spec ring buffer format */
struct __packed hns3_desc {
- __le64 addr;
+ union {
+ __le64 addr;
+ __le16 csum;
+ };
union {
struct {
__le16 vlan_tag;
@@ -366,6 +367,14 @@ enum hns3_pkt_ol4type {
HNS3_OL4_TYPE_UNKNOWN
};
+struct hns3_rx_ptype {
+ u32 ptype:8;
+ u32 csum_level:2;
+ u32 ip_summed:2;
+ u32 l3_type:4;
+ u32 valid:1;
+};
+
struct ring_stats {
u64 sw_err_cnt;
u64 seg_pkt_cnt;
@@ -397,6 +406,7 @@ struct ring_stats {
u64 rx_multicast;
u64 non_reuse_pg;
};
+ __le16 csum;
};
};
@@ -640,9 +650,10 @@ void hns3_dcbnl_setup(struct hnae3_handle *handle);
static inline void hns3_dcbnl_setup(struct hnae3_handle *handle) {}
#endif
-void hns3_dbg_init(struct hnae3_handle *handle);
+int hns3_dbg_init(struct hnae3_handle *handle);
void hns3_dbg_uninit(struct hnae3_handle *handle);
void hns3_dbg_register_debugfs(const char *debugfs_dir_name);
void hns3_dbg_unregister_debugfs(void);
void hns3_shinfo_pack(struct skb_shared_info *shinfo, __u32 *size);
+u16 hns3_get_max_available_channels(struct hnae3_handle *h);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
index 76a482456f1f..6aed30cc22f2 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
@@ -386,6 +386,8 @@ static void hclge_parse_capability(struct hclge_dev *hdev,
set_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps);
if (hnae3_get_bit(caps, HCLGE_CAP_PHY_IMP_B))
set_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps);
+ if (hnae3_get_bit(caps, HCLGE_CAP_RXD_ADV_LAYOUT_B))
+ set_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, ae_dev->caps);
}
static __le32 hclge_build_api_caps(void)
@@ -469,7 +471,7 @@ static int hclge_firmware_compat_config(struct hclge_dev *hdev)
struct hclge_desc desc;
u32 compat = 0;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_COMPAT_CFG, false);
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_COMPAT_CFG, false);
req = (struct hclge_firmware_compat_cmd *)desc.data;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index c6fc22e29581..12558aa0fe0a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -267,10 +267,10 @@ enum hclge_opcode_type {
/* NCL config command */
HCLGE_OPC_QUERY_NCL_CONFIG = 0x7011,
- /* M7 stats command */
- HCLGE_OPC_M7_STATS_BD = 0x7012,
- HCLGE_OPC_M7_STATS_INFO = 0x7013,
- HCLGE_OPC_M7_COMPAT_CFG = 0x701A,
+ /* IMP stats command */
+ HCLGE_OPC_IMP_STATS_BD = 0x7012,
+ HCLGE_OPC_IMP_STATS_INFO = 0x7013,
+ HCLGE_OPC_IMP_COMPAT_CFG = 0x701A,
/* SFP command */
HCLGE_OPC_GET_SFP_EEPROM = 0x7100,
@@ -391,6 +391,7 @@ enum HCLGE_CAP_BITS {
HCLGE_CAP_UDP_TUNNEL_CSUM_B,
HCLGE_CAP_FEC_B = 13,
HCLGE_CAP_PAUSE_B = 14,
+ HCLGE_CAP_RXD_ADV_LAYOUT_B = 15,
};
enum HCLGE_API_CAP_BITS {
@@ -1100,7 +1101,7 @@ struct hclge_fd_user_def_cfg_cmd {
u8 rsv[12];
};
-struct hclge_get_m7_bd_cmd {
+struct hclge_get_imp_bd_cmd {
__le32 bd_num;
u8 rsv[20];
};
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
index 85d306459e36..8a92ab448a19 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
@@ -4,10 +4,16 @@
#include <linux/device.h>
#include "hclge_debugfs.h"
+#include "hclge_err.h"
#include "hclge_main.h"
#include "hclge_tm.h"
#include "hnae3.h"
+static const char * const state_str[] = { "off", "on" };
+static const char * const hclge_mac_state_str[] = {
+ "TO_ADD", "TO_DEL", "ACTIVE"
+};
+
static const struct hclge_dbg_reg_type_info hclge_dbg_reg_info[] = {
{ .reg_type = "bios common",
.dfx_msg = &hclge_dbg_bios_common_reg[0],
@@ -71,6 +77,35 @@ static const struct hclge_dbg_reg_type_info hclge_dbg_reg_info[] = {
.cmd = HCLGE_OPC_DFX_TQP_REG } },
};
+static void hclge_dbg_fill_content(char *content, u16 len,
+ const struct hclge_dbg_item *items,
+ const char **result, u16 size)
+{
+ char *pos = content;
+ u16 i;
+
+ memset(content, ' ', len);
+ for (i = 0; i < size; i++) {
+ if (result)
+ strncpy(pos, result[i], strlen(result[i]));
+ else
+ strncpy(pos, items[i].name, strlen(items[i].name));
+ pos += strlen(items[i].name) + items[i].interval;
+ }
+ *pos++ = '\n';
+ *pos++ = '\0';
+}
+
+static char *hclge_dbg_get_func_id_str(char *buf, u8 id)
+{
+ if (id)
+ sprintf(buf, "vf%u", id - 1);
+ else
+ sprintf(buf, "pf");
+
+ return buf;
+}
+
static int hclge_dbg_get_dfx_bd_num(struct hclge_dev *hdev, int offset)
{
struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT];
@@ -1179,24 +1214,19 @@ err_qos_cmd_send:
"dump qos buf cfg fail(0x%x), ret = %d\n", cmd, ret);
}
-static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev)
+static int hclge_dbg_dump_mng_table(struct hclge_dev *hdev, char *buf, int len)
{
struct hclge_mac_ethertype_idx_rd_cmd *req0;
- char printf_buf[HCLGE_DBG_BUF_LEN];
struct hclge_desc desc;
u32 msg_egress_port;
+ int pos = 0;
int ret, i;
- dev_info(&hdev->pdev->dev, "mng tab:\n");
- memset(printf_buf, 0, HCLGE_DBG_BUF_LEN);
- strncat(printf_buf,
- "entry|mac_addr |mask|ether|mask|vlan|mask",
- HCLGE_DBG_BUF_LEN - 1);
- strncat(printf_buf + strlen(printf_buf),
- "|i_map|i_dir|e_type|pf_id|vf_id|q_id|drop\n",
- HCLGE_DBG_BUF_LEN - strlen(printf_buf) - 1);
-
- dev_info(&hdev->pdev->dev, "%s", printf_buf);
+ pos += scnprintf(buf + pos, len - pos,
+ "entry mac_addr mask ether ");
+ pos += scnprintf(buf + pos, len - pos,
+ "mask vlan mask i_map i_dir e_type ");
+ pos += scnprintf(buf + pos, len - pos, "pf_id vf_id q_id drop\n");
for (i = 0; i < HCLGE_DBG_MNG_TBL_MAX; i++) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_MAC_ETHERTYPE_IDX_RD,
@@ -1207,43 +1237,40 @@ static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev)
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
- "call hclge_cmd_send fail, ret = %d\n", ret);
- return;
+ "failed to dump manage table, ret = %d\n", ret);
+ return ret;
}
if (!req0->resp_code)
continue;
- memset(printf_buf, 0, HCLGE_DBG_BUF_LEN);
- snprintf(printf_buf, HCLGE_DBG_BUF_LEN,
- "%02u |%02x:%02x:%02x:%02x:%02x:%02x|",
- le16_to_cpu(req0->index),
- req0->mac_addr[0], req0->mac_addr[1],
- req0->mac_addr[2], req0->mac_addr[3],
- req0->mac_addr[4], req0->mac_addr[5]);
-
- snprintf(printf_buf + strlen(printf_buf),
- HCLGE_DBG_BUF_LEN - strlen(printf_buf),
- "%x |%04x |%x |%04x|%x |%02x |%02x |",
- !!(req0->flags & HCLGE_DBG_MNG_MAC_MASK_B),
- le16_to_cpu(req0->ethter_type),
- !!(req0->flags & HCLGE_DBG_MNG_ETHER_MASK_B),
- le16_to_cpu(req0->vlan_tag) & HCLGE_DBG_MNG_VLAN_TAG,
- !!(req0->flags & HCLGE_DBG_MNG_VLAN_MASK_B),
- req0->i_port_bitmap, req0->i_port_direction);
+ pos += scnprintf(buf + pos, len - pos, "%02u %pM ",
+ le16_to_cpu(req0->index), req0->mac_addr);
+
+ pos += scnprintf(buf + pos, len - pos,
+ "%x %04x %x %04x ",
+ !!(req0->flags & HCLGE_DBG_MNG_MAC_MASK_B),
+ le16_to_cpu(req0->ethter_type),
+ !!(req0->flags & HCLGE_DBG_MNG_ETHER_MASK_B),
+ le16_to_cpu(req0->vlan_tag) &
+ HCLGE_DBG_MNG_VLAN_TAG);
+
+ pos += scnprintf(buf + pos, len - pos,
+ "%x %02x %02x ",
+ !!(req0->flags & HCLGE_DBG_MNG_VLAN_MASK_B),
+ req0->i_port_bitmap, req0->i_port_direction);
msg_egress_port = le16_to_cpu(req0->egress_port);
- snprintf(printf_buf + strlen(printf_buf),
- HCLGE_DBG_BUF_LEN - strlen(printf_buf),
- "%x |%x |%02x |%04x|%x\n",
- !!(msg_egress_port & HCLGE_DBG_MNG_E_TYPE_B),
- msg_egress_port & HCLGE_DBG_MNG_PF_ID,
- (msg_egress_port >> 3) & HCLGE_DBG_MNG_VF_ID,
- le16_to_cpu(req0->egress_queue),
- !!(msg_egress_port & HCLGE_DBG_MNG_DROP_B));
-
- dev_info(&hdev->pdev->dev, "%s", printf_buf);
+ pos += scnprintf(buf + pos, len - pos,
+ "%x %x %02x %04x %x\n",
+ !!(msg_egress_port & HCLGE_DBG_MNG_E_TYPE_B),
+ msg_egress_port & HCLGE_DBG_MNG_PF_ID,
+ (msg_egress_port >> 3) & HCLGE_DBG_MNG_VF_ID,
+ le16_to_cpu(req0->egress_queue),
+ !!(msg_egress_port & HCLGE_DBG_MNG_DROP_B));
}
+
+ return 0;
}
static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, u8 stage,
@@ -1363,37 +1390,46 @@ static void hclge_dbg_fd_tcam(struct hclge_dev *hdev)
kfree(rule_locs);
}
-void hclge_dbg_dump_rst_info(struct hclge_dev *hdev)
+int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len)
{
- dev_info(&hdev->pdev->dev, "PF reset count: %u\n",
- hdev->rst_stats.pf_rst_cnt);
- dev_info(&hdev->pdev->dev, "FLR reset count: %u\n",
- hdev->rst_stats.flr_rst_cnt);
- dev_info(&hdev->pdev->dev, "GLOBAL reset count: %u\n",
- hdev->rst_stats.global_rst_cnt);
- dev_info(&hdev->pdev->dev, "IMP reset count: %u\n",
- hdev->rst_stats.imp_rst_cnt);
- dev_info(&hdev->pdev->dev, "reset done count: %u\n",
- hdev->rst_stats.reset_done_cnt);
- dev_info(&hdev->pdev->dev, "HW reset done count: %u\n",
- hdev->rst_stats.hw_reset_done_cnt);
- dev_info(&hdev->pdev->dev, "reset count: %u\n",
- hdev->rst_stats.reset_cnt);
- dev_info(&hdev->pdev->dev, "reset fail count: %u\n",
- hdev->rst_stats.reset_fail_cnt);
- dev_info(&hdev->pdev->dev, "vector0 interrupt enable status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_REG_BASE));
- dev_info(&hdev->pdev->dev, "reset interrupt source: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG));
- dev_info(&hdev->pdev->dev, "reset interrupt status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS));
- dev_info(&hdev->pdev->dev, "hardware reset status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG));
- dev_info(&hdev->pdev->dev, "handshake status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG));
- dev_info(&hdev->pdev->dev, "function reset status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING));
- dev_info(&hdev->pdev->dev, "hdev state: 0x%lx\n", hdev->state);
+ int pos = 0;
+
+ pos += scnprintf(buf + pos, len - pos, "PF reset count: %u\n",
+ hdev->rst_stats.pf_rst_cnt);
+ pos += scnprintf(buf + pos, len - pos, "FLR reset count: %u\n",
+ hdev->rst_stats.flr_rst_cnt);
+ pos += scnprintf(buf + pos, len - pos, "GLOBAL reset count: %u\n",
+ hdev->rst_stats.global_rst_cnt);
+ pos += scnprintf(buf + pos, len - pos, "IMP reset count: %u\n",
+ hdev->rst_stats.imp_rst_cnt);
+ pos += scnprintf(buf + pos, len - pos, "reset done count: %u\n",
+ hdev->rst_stats.reset_done_cnt);
+ pos += scnprintf(buf + pos, len - pos, "HW reset done count: %u\n",
+ hdev->rst_stats.hw_reset_done_cnt);
+ pos += scnprintf(buf + pos, len - pos, "reset count: %u\n",
+ hdev->rst_stats.reset_cnt);
+ pos += scnprintf(buf + pos, len - pos, "reset fail count: %u\n",
+ hdev->rst_stats.reset_fail_cnt);
+ pos += scnprintf(buf + pos, len - pos,
+ "vector0 interrupt enable status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_REG_BASE));
+ pos += scnprintf(buf + pos, len - pos, "reset interrupt source: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG));
+ pos += scnprintf(buf + pos, len - pos, "reset interrupt status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS));
+ pos += scnprintf(buf + pos, len - pos, "RAS interrupt status: 0x%x\n",
+ hclge_read_dev(&hdev->hw,
+ HCLGE_RAS_PF_OTHER_INT_STS_REG));
+ pos += scnprintf(buf + pos, len - pos, "hardware reset status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG));
+ pos += scnprintf(buf + pos, len - pos, "handshake status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG));
+ pos += scnprintf(buf + pos, len - pos, "function reset status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING));
+ pos += scnprintf(buf + pos, len - pos, "hdev state: 0x%lx\n",
+ hdev->state);
+
+ return 0;
}
static void hclge_dbg_dump_serv_info(struct hclge_dev *hdev)
@@ -1404,169 +1440,179 @@ static void hclge_dbg_dump_serv_info(struct hclge_dev *hdev)
hdev->serv_processed_cnt);
}
-static void hclge_dbg_dump_interrupt(struct hclge_dev *hdev)
+static int hclge_dbg_dump_interrupt(struct hclge_dev *hdev, char *buf, int len)
{
- dev_info(&hdev->pdev->dev, "num_nic_msi: %u\n", hdev->num_nic_msi);
- dev_info(&hdev->pdev->dev, "num_roce_msi: %u\n", hdev->num_roce_msi);
- dev_info(&hdev->pdev->dev, "num_msi_used: %u\n", hdev->num_msi_used);
- dev_info(&hdev->pdev->dev, "num_msi_left: %u\n", hdev->num_msi_left);
+ int pos = 0;
+
+ pos += scnprintf(buf + pos, len - pos, "num_nic_msi: %u\n",
+ hdev->num_nic_msi);
+ pos += scnprintf(buf + pos, len - pos, "num_roce_msi: %u\n",
+ hdev->num_roce_msi);
+ pos += scnprintf(buf + pos, len - pos, "num_msi_used: %u\n",
+ hdev->num_msi_used);
+ pos += scnprintf(buf + pos, len - pos, "num_msi_left: %u\n",
+ hdev->num_msi_left);
+
+ return 0;
}
-static void hclge_dbg_get_m7_stats_info(struct hclge_dev *hdev)
+static void hclge_dbg_imp_info_data_print(struct hclge_desc *desc_src,
+ char *buf, int len, u32 bd_num)
{
- struct hclge_desc *desc_src, *desc_tmp;
- struct hclge_get_m7_bd_cmd *req;
+#define HCLGE_DBG_IMP_INFO_PRINT_OFFSET 0x2
+
+ struct hclge_desc *desc_index = desc_src;
+ u32 offset = 0;
+ int pos = 0;
+ u32 i, j;
+
+ pos += scnprintf(buf + pos, len - pos, "offset | data\n");
+
+ for (i = 0; i < bd_num; i++) {
+ j = 0;
+ while (j < HCLGE_DESC_DATA_LEN - 1) {
+ pos += scnprintf(buf + pos, len - pos, "0x%04x | ",
+ offset);
+ pos += scnprintf(buf + pos, len - pos, "0x%08x ",
+ le32_to_cpu(desc_index->data[j++]));
+ pos += scnprintf(buf + pos, len - pos, "0x%08x\n",
+ le32_to_cpu(desc_index->data[j++]));
+ offset += sizeof(u32) * HCLGE_DBG_IMP_INFO_PRINT_OFFSET;
+ }
+ desc_index++;
+ }
+}
+
+static int
+hclge_dbg_get_imp_stats_info(struct hclge_dev *hdev, char *buf, int len)
+{
+ struct hclge_get_imp_bd_cmd *req;
+ struct hclge_desc *desc_src;
struct hclge_desc desc;
- u32 bd_num, buf_len;
- int ret, i;
+ u32 bd_num;
+ int ret;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_STATS_BD, true);
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_STATS_BD, true);
- req = (struct hclge_get_m7_bd_cmd *)desc.data;
+ req = (struct hclge_get_imp_bd_cmd *)desc.data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
- "get firmware statistics bd number failed, ret = %d\n",
+ "failed to get imp statistics bd number, ret = %d\n",
ret);
- return;
+ return ret;
}
bd_num = le32_to_cpu(req->bd_num);
- buf_len = sizeof(struct hclge_desc) * bd_num;
- desc_src = kzalloc(buf_len, GFP_KERNEL);
+ desc_src = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
if (!desc_src)
- return;
+ return -ENOMEM;
- desc_tmp = desc_src;
- ret = hclge_dbg_cmd_send(hdev, desc_tmp, 0, bd_num,
- HCLGE_OPC_M7_STATS_INFO);
+ ret = hclge_dbg_cmd_send(hdev, desc_src, 0, bd_num,
+ HCLGE_OPC_IMP_STATS_INFO);
if (ret) {
kfree(desc_src);
dev_err(&hdev->pdev->dev,
- "get firmware statistics failed, ret = %d\n", ret);
- return;
+ "failed to get imp statistics, ret = %d\n", ret);
+ return ret;
}
- for (i = 0; i < bd_num; i++) {
- dev_info(&hdev->pdev->dev, "0x%08x 0x%08x 0x%08x\n",
- le32_to_cpu(desc_tmp->data[0]),
- le32_to_cpu(desc_tmp->data[1]),
- le32_to_cpu(desc_tmp->data[2]));
- dev_info(&hdev->pdev->dev, "0x%08x 0x%08x 0x%08x\n",
- le32_to_cpu(desc_tmp->data[3]),
- le32_to_cpu(desc_tmp->data[4]),
- le32_to_cpu(desc_tmp->data[5]));
-
- desc_tmp++;
- }
+ hclge_dbg_imp_info_data_print(desc_src, buf, len, bd_num);
kfree(desc_src);
+
+ return 0;
}
#define HCLGE_CMD_NCL_CONFIG_BD_NUM 5
+#define HCLGE_MAX_NCL_CONFIG_LENGTH 16384
-static void hclge_ncl_config_data_print(struct hclge_dev *hdev,
- struct hclge_desc *desc, int *offset,
- int *length)
+static void hclge_ncl_config_data_print(struct hclge_desc *desc, int *index,
+ char *buf, int *len, int *pos)
{
#define HCLGE_CMD_DATA_NUM 6
- int i;
- int j;
+ int offset = HCLGE_MAX_NCL_CONFIG_LENGTH - *index;
+ int i, j;
for (i = 0; i < HCLGE_CMD_NCL_CONFIG_BD_NUM; i++) {
for (j = 0; j < HCLGE_CMD_DATA_NUM; j++) {
if (i == 0 && j == 0)
continue;
- dev_info(&hdev->pdev->dev, "0x%04x | 0x%08x\n",
- *offset,
- le32_to_cpu(desc[i].data[j]));
- *offset += sizeof(u32);
- *length -= sizeof(u32);
- if (*length <= 0)
+ *pos += scnprintf(buf + *pos, *len - *pos,
+ "0x%04x | 0x%08x\n", offset,
+ le32_to_cpu(desc[i].data[j]));
+
+ offset += sizeof(u32);
+ *index -= sizeof(u32);
+
+ if (*index <= 0)
return;
}
}
}
-/* hclge_dbg_dump_ncl_config: print specified range of NCL_CONFIG file
- * @hdev: pointer to struct hclge_dev
- * @cmd_buf: string that contains offset and length
- */
-static void hclge_dbg_dump_ncl_config(struct hclge_dev *hdev,
- const char *cmd_buf)
+static int
+hclge_dbg_dump_ncl_config(struct hclge_dev *hdev, char *buf, int len)
{
-#define HCLGE_MAX_NCL_CONFIG_OFFSET 4096
#define HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD (20 + 24 * 4)
-#define HCLGE_NCL_CONFIG_PARAM_NUM 2
struct hclge_desc desc[HCLGE_CMD_NCL_CONFIG_BD_NUM];
int bd_num = HCLGE_CMD_NCL_CONFIG_BD_NUM;
- int offset;
- int length;
- int data0;
+ int index = HCLGE_MAX_NCL_CONFIG_LENGTH;
+ int pos = 0;
+ u32 data0;
int ret;
- ret = sscanf(cmd_buf, "%x %x", &offset, &length);
- if (ret != HCLGE_NCL_CONFIG_PARAM_NUM) {
- dev_err(&hdev->pdev->dev,
- "Too few parameters, num = %d.\n", ret);
- return;
- }
-
- if (offset < 0 || offset >= HCLGE_MAX_NCL_CONFIG_OFFSET ||
- length <= 0 || length > HCLGE_MAX_NCL_CONFIG_OFFSET - offset) {
- dev_err(&hdev->pdev->dev,
- "Invalid input, offset = %d, length = %d.\n",
- offset, length);
- return;
- }
+ pos += scnprintf(buf + pos, len - pos, "offset | data\n");
- dev_info(&hdev->pdev->dev, "offset | data\n");
-
- while (length > 0) {
- data0 = offset;
- if (length >= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD)
+ while (index > 0) {
+ data0 = HCLGE_MAX_NCL_CONFIG_LENGTH - index;
+ if (index >= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD)
data0 |= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD << 16;
else
- data0 |= length << 16;
+ data0 |= (u32)index << 16;
ret = hclge_dbg_cmd_send(hdev, desc, data0, bd_num,
HCLGE_OPC_QUERY_NCL_CONFIG);
if (ret)
- return;
+ return ret;
- hclge_ncl_config_data_print(hdev, desc, &offset, &length);
+ hclge_ncl_config_data_print(desc, &index, buf, &len, &pos);
}
+
+ return 0;
}
-static void hclge_dbg_dump_loopback(struct hclge_dev *hdev)
+static int hclge_dbg_dump_loopback(struct hclge_dev *hdev, char *buf, int len)
{
struct phy_device *phydev = hdev->hw.mac.phydev;
struct hclge_config_mac_mode_cmd *req_app;
struct hclge_common_lb_cmd *req_common;
struct hclge_desc desc;
u8 loopback_en;
+ int pos = 0;
int ret;
req_app = (struct hclge_config_mac_mode_cmd *)desc.data;
req_common = (struct hclge_common_lb_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "mac id: %u\n", hdev->hw.mac.mac_id);
+ pos += scnprintf(buf + pos, len - pos, "mac id: %u\n",
+ hdev->hw.mac.mac_id);
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to dump app loopback status, ret = %d\n", ret);
- return;
+ return ret;
}
loopback_en = hnae3_get_bit(le32_to_cpu(req_app->txrx_pad_fcs_loop_en),
HCLGE_MAC_APP_LP_B);
- dev_info(&hdev->pdev->dev, "app loopback: %s\n",
- loopback_en ? "on" : "off");
+ pos += scnprintf(buf + pos, len - pos, "app loopback: %s\n",
+ state_str[loopback_en]);
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMMON_LOOPBACK, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -1574,27 +1620,30 @@ static void hclge_dbg_dump_loopback(struct hclge_dev *hdev)
dev_err(&hdev->pdev->dev,
"failed to dump common loopback status, ret = %d\n",
ret);
- return;
+ return ret;
}
loopback_en = req_common->enable & HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
- dev_info(&hdev->pdev->dev, "serdes serial loopback: %s\n",
- loopback_en ? "on" : "off");
+ pos += scnprintf(buf + pos, len - pos, "serdes serial loopback: %s\n",
+ state_str[loopback_en]);
loopback_en = req_common->enable &
- HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B;
- dev_info(&hdev->pdev->dev, "serdes parallel loopback: %s\n",
- loopback_en ? "on" : "off");
+ HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B ? 1 : 0;
+ pos += scnprintf(buf + pos, len - pos, "serdes parallel loopback: %s\n",
+ state_str[loopback_en]);
if (phydev) {
- dev_info(&hdev->pdev->dev, "phy loopback: %s\n",
- phydev->loopback_enabled ? "on" : "off");
+ loopback_en = phydev->loopback_enabled;
+ pos += scnprintf(buf + pos, len - pos, "phy loopback: %s\n",
+ state_str[loopback_en]);
} else if (hnae3_dev_phy_imp_supported(hdev)) {
loopback_en = req_common->enable &
HCLGE_CMD_GE_PHY_INNER_LOOP_B;
- dev_info(&hdev->pdev->dev, "phy loopback: %s\n",
- loopback_en ? "on" : "off");
+ pos += scnprintf(buf + pos, len - pos, "phy loopback: %s\n",
+ state_str[loopback_en]);
}
+
+ return 0;
}
/* hclge_dbg_dump_mac_tnl_status: print message about mac tnl interrupt
@@ -1693,45 +1742,65 @@ static void hclge_dbg_dump_qs_shaper(struct hclge_dev *hdev,
hclge_dbg_dump_qs_shaper_single(hdev, qsid);
}
-static int hclge_dbg_dump_mac_list(struct hclge_dev *hdev, const char *cmd_buf,
- bool is_unicast)
+static const struct hclge_dbg_item mac_list_items[] = {
+ { "FUNC_ID", 2 },
+ { "MAC_ADDR", 12 },
+ { "STATE", 2 },
+};
+
+static void hclge_dbg_dump_mac_list(struct hclge_dev *hdev, char *buf, int len,
+ bool is_unicast)
{
+ char data_str[ARRAY_SIZE(mac_list_items)][HCLGE_DBG_DATA_STR_LEN];
+ char content[HCLGE_DBG_INFO_LEN], str_id[HCLGE_DBG_ID_LEN];
+ char *result[ARRAY_SIZE(mac_list_items)];
struct hclge_mac_node *mac_node, *tmp;
struct hclge_vport *vport;
struct list_head *list;
u32 func_id;
- int ret;
-
- ret = kstrtouint(cmd_buf, 0, &func_id);
- if (ret < 0) {
- dev_err(&hdev->pdev->dev,
- "dump mac list: bad command string, ret = %d\n", ret);
- return -EINVAL;
- }
+ int pos = 0;
+ int i;
- if (func_id >= hdev->num_alloc_vport) {
- dev_err(&hdev->pdev->dev,
- "function id(%u) is out of range(0-%u)\n", func_id,
- hdev->num_alloc_vport - 1);
- return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(mac_list_items); i++)
+ result[i] = &data_str[i][0];
+
+ pos += scnprintf(buf + pos, len - pos, "%s MAC_LIST:\n",
+ is_unicast ? "UC" : "MC");
+ hclge_dbg_fill_content(content, sizeof(content), mac_list_items,
+ NULL, ARRAY_SIZE(mac_list_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+
+ for (func_id = 0; func_id < hdev->num_alloc_vport; func_id++) {
+ vport = &hdev->vport[func_id];
+ list = is_unicast ? &vport->uc_mac_list : &vport->mc_mac_list;
+ spin_lock_bh(&vport->mac_list_lock);
+ list_for_each_entry_safe(mac_node, tmp, list, node) {
+ i = 0;
+ result[i++] = hclge_dbg_get_func_id_str(str_id,
+ func_id);
+ sprintf(result[i++], "%pM", mac_node->mac_addr);
+ sprintf(result[i++], "%5s",
+ hclge_mac_state_str[mac_node->state]);
+ hclge_dbg_fill_content(content, sizeof(content),
+ mac_list_items,
+ (const char **)result,
+ ARRAY_SIZE(mac_list_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+ }
+ spin_unlock_bh(&vport->mac_list_lock);
}
+}
- vport = &hdev->vport[func_id];
-
- list = is_unicast ? &vport->uc_mac_list : &vport->mc_mac_list;
-
- dev_info(&hdev->pdev->dev, "vport %u %s mac list:\n",
- func_id, is_unicast ? "uc" : "mc");
- dev_info(&hdev->pdev->dev, "mac address state\n");
-
- spin_lock_bh(&vport->mac_list_lock);
+static int hclge_dbg_dump_mac_uc(struct hclge_dev *hdev, char *buf, int len)
+{
+ hclge_dbg_dump_mac_list(hdev, buf, len, true);
- list_for_each_entry_safe(mac_node, tmp, list, node) {
- dev_info(&hdev->pdev->dev, "%pM %d\n",
- mac_node->mac_addr, mac_node->state);
- }
+ return 0;
+}
- spin_unlock_bh(&vport->mac_list_lock);
+static int hclge_dbg_dump_mac_mc(struct hclge_dev *hdev, char *buf, int len)
+{
+ hclge_dbg_dump_mac_list(hdev, buf, len, false);
return 0;
}
@@ -1740,8 +1809,6 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
{
#define DUMP_REG "dump reg"
#define DUMP_TM_MAP "dump tm map"
-#define DUMP_LOOPBACK "dump loopback"
-#define DUMP_INTERRUPT "dump intr"
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
@@ -1760,38 +1827,15 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
hclge_dbg_dump_qos_pri_map(hdev);
} else if (strncmp(cmd_buf, "dump qos buf cfg", 16) == 0) {
hclge_dbg_dump_qos_buf_cfg(hdev);
- } else if (strncmp(cmd_buf, "dump mng tbl", 12) == 0) {
- hclge_dbg_dump_mng_table(hdev);
} else if (strncmp(cmd_buf, DUMP_REG, strlen(DUMP_REG)) == 0) {
hclge_dbg_dump_reg_cmd(hdev, &cmd_buf[sizeof(DUMP_REG)]);
- } else if (strncmp(cmd_buf, "dump reset info", 15) == 0) {
- hclge_dbg_dump_rst_info(hdev);
} else if (strncmp(cmd_buf, "dump serv info", 14) == 0) {
hclge_dbg_dump_serv_info(hdev);
- } else if (strncmp(cmd_buf, "dump m7 info", 12) == 0) {
- hclge_dbg_get_m7_stats_info(hdev);
- } else if (strncmp(cmd_buf, "dump ncl_config", 15) == 0) {
- hclge_dbg_dump_ncl_config(hdev,
- &cmd_buf[sizeof("dump ncl_config")]);
} else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) {
hclge_dbg_dump_mac_tnl_status(hdev);
- } else if (strncmp(cmd_buf, DUMP_LOOPBACK,
- strlen(DUMP_LOOPBACK)) == 0) {
- hclge_dbg_dump_loopback(hdev);
} else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) {
hclge_dbg_dump_qs_shaper(hdev,
&cmd_buf[sizeof("dump qs shaper")]);
- } else if (strncmp(cmd_buf, "dump uc mac list", 16) == 0) {
- hclge_dbg_dump_mac_list(hdev,
- &cmd_buf[sizeof("dump uc mac list")],
- true);
- } else if (strncmp(cmd_buf, "dump mc mac list", 16) == 0) {
- hclge_dbg_dump_mac_list(hdev,
- &cmd_buf[sizeof("dump mc mac list")],
- false);
- } else if (strncmp(cmd_buf, DUMP_INTERRUPT,
- strlen(DUMP_INTERRUPT)) == 0) {
- hclge_dbg_dump_interrupt(hdev);
} else {
dev_info(&hdev->pdev->dev, "unknown command\n");
return -EINVAL;
@@ -1800,21 +1844,65 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
return 0;
}
-int hclge_dbg_read_cmd(struct hnae3_handle *handle, const char *cmd_buf,
+static const struct hclge_dbg_func hclge_dbg_cmd_func[] = {
+ {
+ .cmd = HNAE3_DBG_CMD_TM_NODES,
+ .dbg_dump = hclge_dbg_dump_tm_nodes,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TM_PRI,
+ .dbg_dump = hclge_dbg_dump_tm_pri,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TM_QSET,
+ .dbg_dump = hclge_dbg_dump_tm_qset,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_MAC_UC,
+ .dbg_dump = hclge_dbg_dump_mac_uc,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_MAC_MC,
+ .dbg_dump = hclge_dbg_dump_mac_mc,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_MNG_TBL,
+ .dbg_dump = hclge_dbg_dump_mng_table,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_LOOPBACK,
+ .dbg_dump = hclge_dbg_dump_loopback,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_INTERRUPT_INFO,
+ .dbg_dump = hclge_dbg_dump_interrupt,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_RESET_INFO,
+ .dbg_dump = hclge_dbg_dump_rst_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_IMP_INFO,
+ .dbg_dump = hclge_dbg_get_imp_stats_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_NCL_CONFIG,
+ .dbg_dump = hclge_dbg_dump_ncl_config,
+ },
+};
+
+int hclge_dbg_read_cmd(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
+ u32 i;
- if (strncmp(cmd_buf, HNAE3_DBG_TM_NODES,
- strlen(HNAE3_DBG_TM_NODES)) == 0)
- return hclge_dbg_dump_tm_nodes(hdev, buf, len);
- else if (strncmp(cmd_buf, HNAE3_DBG_TM_PRI,
- strlen(HNAE3_DBG_TM_PRI)) == 0)
- return hclge_dbg_dump_tm_pri(hdev, buf, len);
- else if (strncmp(cmd_buf, HNAE3_DBG_TM_QSET,
- strlen(HNAE3_DBG_TM_QSET)) == 0)
- return hclge_dbg_dump_tm_qset(hdev, buf, len);
+ for (i = 0; i < ARRAY_SIZE(hclge_dbg_cmd_func); i++) {
+ if (cmd == hclge_dbg_cmd_func[i].cmd)
+ return hclge_dbg_cmd_func[i].dbg_dump(hdev, buf, len);
+ }
+ dev_err(&hdev->pdev->dev, "invalid command(%d)\n", cmd);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
index ca2ab6cf84d9..bf6a0ff66047 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
@@ -7,7 +7,6 @@
#include <linux/etherdevice.h>
#include "hclge_cmd.h"
-#define HCLGE_DBG_BUF_LEN 256
#define HCLGE_DBG_MNG_TBL_MAX 64
#define HCLGE_DBG_MNG_VLAN_MASK_B BIT(0)
@@ -83,6 +82,11 @@ struct hclge_dbg_reg_type_info {
struct hclge_dbg_reg_common_msg reg_msg;
};
+struct hclge_dbg_func {
+ enum hnae3_dbg_cmd cmd;
+ int (*dbg_dump)(struct hclge_dev *hdev, char *buf, int len);
+};
+
static const struct hclge_dbg_dfx_message hclge_dbg_bios_common_reg[] = {
{false, "Reserved"},
{true, "BP_CPU_STATE"},
@@ -723,4 +727,13 @@ static const struct hclge_dbg_dfx_message hclge_dbg_tqp_reg[] = {
{true, "RCB_CFG_TX_RING_EBDNUM"},
};
+#define HCLGE_DBG_INFO_LEN 256
+#define HCLGE_DBG_ID_LEN 16
+#define HCLGE_DBG_ITEM_NAME_LEN 32
+#define HCLGE_DBG_DATA_STR_LEN 32
+struct hclge_dbg_item {
+ char name[HCLGE_DBG_ITEM_NAME_LEN];
+ u16 interval; /* blank numbers after the item */
+};
+
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 6304aed49f22..d4d3f0b247af 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -3936,6 +3936,21 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
return ret;
}
+static void hclge_show_rst_info(struct hclge_dev *hdev)
+{
+ char *buf;
+
+ buf = kzalloc(HCLGE_DBG_RESET_INFO_LEN, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ hclge_dbg_dump_rst_info(hdev, buf, HCLGE_DBG_RESET_INFO_LEN);
+
+ dev_info(&hdev->pdev->dev, "dump reset info:\n%s", buf);
+
+ kfree(buf);
+}
+
static bool hclge_reset_err_handle(struct hclge_dev *hdev)
{
#define MAX_RESET_FAIL_CNT 5
@@ -3966,7 +3981,7 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev)
dev_err(&hdev->pdev->dev, "Reset fail!\n");
- hclge_dbg_dump_rst_info(hdev);
+ hclge_show_rst_info(hdev);
set_bit(HCLGE_STATE_RST_FAIL, &hdev->state);
@@ -11167,6 +11182,18 @@ static void hclge_clear_resetting_state(struct hclge_dev *hdev)
}
}
+static void hclge_init_rxd_adv_layout(struct hclge_dev *hdev)
+{
+ if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
+ hclge_write_dev(&hdev->hw, HCLGE_RXD_ADV_LAYOUT_EN_REG, 1);
+}
+
+static void hclge_uninit_rxd_adv_layout(struct hclge_dev *hdev)
+{
+ if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
+ hclge_write_dev(&hdev->hw, HCLGE_RXD_ADV_LAYOUT_EN_REG, 0);
+}
+
static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
{
struct pci_dev *pdev = ae_dev->pdev;
@@ -11339,6 +11366,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL);
}
+ hclge_init_rxd_adv_layout(hdev);
+
/* Enable MISC vector(vector0) */
hclge_enable_vector(&hdev->misc_vector, true);
@@ -11720,6 +11749,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
if (ret)
return ret;
+ hclge_init_rxd_adv_layout(hdev);
+
dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
HCLGE_DRIVER_NAME);
@@ -11735,6 +11766,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
hclge_clear_vf_vlan(hdev);
hclge_misc_affinity_teardown(hdev);
hclge_state_uninit(hdev);
+ hclge_uninit_rxd_adv_layout(hdev);
hclge_uninit_mac_table(hdev);
hclge_del_all_fd_entries(hdev);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
index ff1d47308c2d..8bf451ef0b05 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -53,6 +53,7 @@
/* bar registers for common func */
#define HCLGE_VECTOR0_OTER_EN_REG 0x20600
#define HCLGE_GRO_EN_REG 0x28000
+#define HCLGE_RXD_ADV_LAYOUT_EN_REG 0x28008
/* bar registers for rcb */
#define HCLGE_RING_RX_ADDR_L_REG 0x80000
@@ -147,6 +148,8 @@
#define HCLGE_MAX_QSET_NUM 1024
+#define HCLGE_DBG_RESET_INFO_LEN 1024
+
enum HLCGE_PORT_TYPE {
HOST_PORT,
NETWORK_PORT
@@ -1060,7 +1063,7 @@ int hclge_vport_start(struct hclge_vport *vport);
void hclge_vport_stop(struct hclge_vport *vport);
int hclge_set_vport_mtu(struct hclge_vport *vport, int new_mtu);
int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf);
-int hclge_dbg_read_cmd(struct hnae3_handle *handle, const char *cmd_buf,
+int hclge_dbg_read_cmd(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len);
u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle, u16 queue_id);
int hclge_notify_client(struct hclge_dev *hdev,
@@ -1088,6 +1091,6 @@ int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev,
void hclge_report_hw_error(struct hclge_dev *hdev,
enum hnae3_hw_error_type type);
void hclge_inform_vf_promisc_info(struct hclge_vport *vport);
-void hclge_dbg_dump_rst_info(struct hclge_dev *hdev);
+int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len);
int hclge_push_vf_link_status(struct hclge_vport *vport);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
index d8c5c5810b99..bd19a2d89f6c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
@@ -359,6 +359,8 @@ static void hclgevf_parse_capability(struct hclgevf_dev *hdev,
set_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps);
if (hnae3_get_bit(caps, HCLGEVF_CAP_UDP_TUNNEL_CSUM_B))
set_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, ae_dev->caps);
+ if (hnae3_get_bit(caps, HCLGEVF_CAP_RXD_ADV_LAYOUT_B))
+ set_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, ae_dev->caps);
}
static __le32 hclgevf_build_api_caps(void)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
index c6dc11b32aa7..202feb70dba5 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
@@ -159,6 +159,7 @@ enum HCLGEVF_CAP_BITS {
HCLGEVF_CAP_HW_PAD_B,
HCLGEVF_CAP_STASH_B,
HCLGEVF_CAP_UDP_TUNNEL_CSUM_B,
+ HCLGEVF_CAP_RXD_ADV_LAYOUT_B = 15,
};
enum HCLGEVF_API_CAP_BITS {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
index 0db51ef15ef6..7bef6b24e610 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -3242,6 +3242,18 @@ static int hclgevf_clear_vport_list(struct hclgevf_dev *hdev)
return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0);
}
+static void hclgevf_init_rxd_adv_layout(struct hclgevf_dev *hdev)
+{
+ if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
+ hclgevf_write_dev(&hdev->hw, HCLGEVF_RXD_ADV_LAYOUT_EN_REG, 1);
+}
+
+static void hclgevf_uninit_rxd_adv_layout(struct hclgevf_dev *hdev)
+{
+ if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
+ hclgevf_write_dev(&hdev->hw, HCLGEVF_RXD_ADV_LAYOUT_EN_REG, 0);
+}
+
static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
{
struct pci_dev *pdev = hdev->pdev;
@@ -3279,6 +3291,8 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
set_bit(HCLGEVF_STATE_PROMISC_CHANGED, &hdev->state);
+ hclgevf_init_rxd_adv_layout(hdev);
+
dev_info(&hdev->pdev->dev, "Reset done\n");
return 0;
@@ -3379,6 +3393,8 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
goto err_config;
}
+ hclgevf_init_rxd_adv_layout(hdev);
+
hdev->last_reset_time = jiffies;
dev_info(&hdev->pdev->dev, "finished initializing %s driver\n",
HCLGEVF_DRIVER_NAME);
@@ -3405,6 +3421,7 @@ static void hclgevf_uninit_hdev(struct hclgevf_dev *hdev)
struct hclge_vf_to_pf_msg send_msg;
hclgevf_state_uninit(hdev);
+ hclgevf_uninit_rxd_adv_layout(hdev);
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_VF_UNINIT, 0);
hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
index 265c9b0b4728..b146d04526de 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
@@ -47,6 +47,7 @@
/* bar registers for common func */
#define HCLGEVF_GRO_EN_REG 0x28000
+#define HCLGEVF_RXD_ADV_LAYOUT_EN_REG 0x28008
/* bar registers for rcb */
#define HCLGEVF_RING_RX_ADDR_L_REG 0x80000
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
index dc024ef521c0..162d3c330dec 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
@@ -1663,7 +1663,6 @@ static void hinic_diag_test(struct net_device *netdev,
err = hinic_port_link_state(nic_dev, &link_state);
if (!err && link_state == HINIC_LINK_STATE_UP)
netif_carrier_on(netdev);
-
}
static int hinic_set_phys_id(struct net_device *netdev,
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
index 5a6bbee819cd..307a6d4af993 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
@@ -223,7 +223,7 @@ static void cmdq_prepare_wqe_ctrl(struct hinic_cmdq_wqe *wqe, int wrapped,
saved_data = CMDQ_WQE_HEADER(wqe)->saved_data;
saved_data = HINIC_SAVED_DATA_CLEAR(saved_data, ARM);
- if ((cmd == CMDQ_SET_ARM_CMD) && (mod == HINIC_MOD_COMM))
+ if (cmd == CMDQ_SET_ARM_CMD && mod == HINIC_MOD_COMM)
CMDQ_WQE_HEADER(wqe)->saved_data |=
HINIC_SAVED_DATA_SET(1, ARM);
else
@@ -594,7 +594,7 @@ static void cmdq_update_errcode(struct hinic_cmdq *cmdq, u16 prod_idx,
}
/**
- * cmdq_arm_ceq_handler - cmdq completion event handler for sync command
+ * cmdq_sync_cmd_handler - cmdq completion event handler for sync command
* @cmdq: the cmdq of the command
* @cons_idx: the consumer index to update the error code for
* @errcode: the error code
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
index 0c74f6674634..428108eb10d2 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
@@ -48,7 +48,7 @@ enum io_status {
};
/**
- * get_capability - convert device capabilities to NIC capabilities
+ * parse_capability - convert device capabilities to NIC capabilities
* @hwdev: the HW device to set and convert device capabilities for
* @dev_cap: device capabilities from FW
*
@@ -92,7 +92,7 @@ static int parse_capability(struct hinic_hwdev *hwdev,
}
/**
- * get_cap_from_fw - get device capabilities from FW
+ * get_capability - get device capabilities from FW
* @pfhwdev: the PF HW device to get capabilities for
*
* Return 0 - Success, negative - Failure
@@ -257,7 +257,7 @@ static int init_fw_ctxt(struct hinic_hwdev *hwdev)
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_FWCTXT_INIT,
&fw_ctxt, sizeof(fw_ctxt),
&fw_ctxt, &out_size);
- if (err || (out_size != sizeof(fw_ctxt)) || fw_ctxt.status) {
+ if (err || out_size != sizeof(fw_ctxt) || fw_ctxt.status) {
dev_err(&pdev->dev, "Failed to init FW ctxt, err: %d, status: 0x%x, out size: 0x%x\n",
err, fw_ctxt.status, out_size);
return -EIO;
@@ -346,7 +346,7 @@ static int wait_for_db_state(struct hinic_hwdev *hwdev)
}
/**
- * clear_io_resource - set the IO resources as not active in the NIC
+ * clear_io_resources - set the IO resources as not active in the NIC
* @hwdev: the NIC HW device
*
* Return 0 - Success, negative - Failure
@@ -424,7 +424,7 @@ static int get_base_qpn(struct hinic_hwdev *hwdev, u16 *base_qpn)
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_GLOBAL_QPN,
&cmd_base_qpn, sizeof(cmd_base_qpn),
&cmd_base_qpn, &out_size);
- if (err || (out_size != sizeof(cmd_base_qpn)) || cmd_base_qpn.status) {
+ if (err || out_size != sizeof(cmd_base_qpn) || cmd_base_qpn.status) {
dev_err(&pdev->dev, "Failed to get base qpn, err: %d, status: 0x%x, out size: 0x%x\n",
err, cmd_base_qpn.status, out_size);
return -EIO;
@@ -605,8 +605,8 @@ static void nic_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in,
hwif = hwdev->hwif;
pdev = hwif->pdev;
- if ((cmd < HINIC_MGMT_MSG_CMD_BASE) ||
- (cmd >= HINIC_MGMT_MSG_CMD_MAX)) {
+ if (cmd < HINIC_MGMT_MSG_CMD_BASE ||
+ cmd >= HINIC_MGMT_MSG_CMD_MAX) {
dev_err(&pdev->dev, "unknown L2NIC event, cmd = %d\n", cmd);
return;
}
@@ -619,7 +619,7 @@ static void nic_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in,
HINIC_CB_ENABLED,
HINIC_CB_ENABLED | HINIC_CB_RUNNING);
- if ((cb_state == HINIC_CB_ENABLED) && (nic_cb->handler))
+ if (cb_state == HINIC_CB_ENABLED && nic_cb->handler)
nic_cb->handler(nic_cb->handle, buf_in,
in_size, buf_out, out_size);
else
@@ -1090,7 +1090,7 @@ struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i)
}
/**
- * hinic_hwdev_get_sq - get RQ
+ * hinic_hwdev_get_rq - get RQ
* @hwdev: the NIC HW device
* @i: the position of the RQ
*
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
index 19942fef99d9..d3fc05a07fdb 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
@@ -254,8 +254,8 @@ static void aeq_irq_handler(struct hinic_eq *eq)
HINIC_EQE_ENABLED,
HINIC_EQE_ENABLED |
HINIC_EQE_RUNNING);
- if ((eqe_state == HINIC_EQE_ENABLED) &&
- (hwe_cb->hwe_handler))
+ if (eqe_state == HINIC_EQE_ENABLED &&
+ hwe_cb->hwe_handler)
hwe_cb->hwe_handler(hwe_cb->handle,
aeqe_curr->data, size);
else
@@ -299,7 +299,7 @@ static void ceq_event_handler(struct hinic_ceqs *ceqs, u32 ceqe)
HINIC_EQE_ENABLED,
HINIC_EQE_ENABLED | HINIC_EQE_RUNNING);
- if ((eqe_state == HINIC_EQE_ENABLED) && (ceq_cb->handler))
+ if (eqe_state == HINIC_EQE_ENABLED && ceq_cb->handler)
ceq_cb->handler(ceq_cb->handle, CEQE_DATA(ceqe));
else
dev_err(&pdev->dev, "Unhandled CEQ Event %d\n", event);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
index cab38ff0713c..0428faa68e80 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
@@ -334,7 +334,7 @@ static void set_dma_attr(struct hinic_hwif *hwif, u32 entry_idx,
}
/**
- * dma_attr_table_init - initialize the default dma attributes
+ * dma_attr_init - initialize the default dma attributes
* @hwif: the HW interface of a pci function device
**/
static void dma_attr_init(struct hinic_hwif *hwif)
@@ -395,7 +395,7 @@ static void __print_selftest_reg(struct hinic_hwif *hwif)
/**
* hinic_init_hwif - initialize the hw interface
* @hwif: the HW interface of a pci function device
- * @pdev: the pci device for acessing PCI resources
+ * @pdev: the pci device for accessing PCI resources
*
* Return 0 - Success, negative - Failure
**/
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
index 4ef4008e65bd..a6e43d686293 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
@@ -137,7 +137,7 @@ static int write_sq_ctxts(struct hinic_func_to_io *func_to_io, u16 base_qpn,
err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
IO_CMD_MODIFY_QUEUE_CTXT, &cmdq_buf,
&out_param);
- if ((err) || (out_param != 0)) {
+ if (err || out_param != 0) {
dev_err(&pdev->dev, "Failed to set SQ ctxts\n");
err = -EFAULT;
}
@@ -181,7 +181,7 @@ static int write_rq_ctxts(struct hinic_func_to_io *func_to_io, u16 base_qpn,
err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
IO_CMD_MODIFY_QUEUE_CTXT, &cmdq_buf,
&out_param);
- if ((err) || (out_param != 0)) {
+ if (err || out_param != 0) {
dev_err(&pdev->dev, "Failed to set RQ ctxts\n");
err = -EFAULT;
}
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
index 817173f1fbb7..ebc77771f5da 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
@@ -294,7 +294,7 @@ static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
goto unlock_sync_msg;
}
- if ((buf_out) && (recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE)) {
+ if (buf_out && recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE) {
memcpy(buf_out, recv_msg->msg, recv_msg->msg_len);
*out_size = recv_msg->msg_len;
}
@@ -411,7 +411,7 @@ static void recv_mgmt_msg_work_handler(struct work_struct *work)
HINIC_MGMT_CB_ENABLED,
HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING);
- if ((cb_state == HINIC_MGMT_CB_ENABLED) && (mgmt_cb->cb))
+ if (cb_state == HINIC_MGMT_CB_ENABLED && mgmt_cb->cb)
mgmt_cb->cb(mgmt_cb->handle, mgmt_work->cmd,
mgmt_work->msg, mgmt_work->msg_len,
buf_out, &out_size);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
index dcba4d009bad..336248aa2e48 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
@@ -894,7 +894,7 @@ struct hinic_rq_wqe *hinic_rq_read_next_wqe(struct hinic_rq *rq,
}
/**
- * hinic_put_wqe - release the ci for new wqes
+ * hinic_rq_put_wqe - release the ci for new wqes
* @rq: recv queue
* @cons_idx: consumer index of the wqe
* @wqe_size: the size of the wqe
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
index 5dc3743f8091..7f0f1aa3cedd 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
@@ -89,6 +89,7 @@ static inline int WQE_PAGE_NUM(struct hinic_wq *wq, u16 idx)
return (((idx) >> ((wq)->wqebbs_per_page_shift))
& ((wq)->num_q_pages - 1));
}
+
/**
* queue_alloc_page - allocate page for Queue
* @hwif: HW interface for allocating DMA
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
index 9a9b09401d01..405ee4d2d2b1 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -172,7 +172,6 @@ static int create_txqs(struct hinic_dev *nic_dev)
"Failed to add SQ%d debug\n", i);
goto err_add_sq_dbg;
}
-
}
return 0;
@@ -233,7 +232,7 @@ static void free_txqs(struct hinic_dev *nic_dev)
}
/**
- * create_txqs - Create the Logical Rx Queues of specific NIC device
+ * create_rxqs - Create the Logical Rx Queues of specific NIC device
* @nic_dev: the specific NIC device
*
* Return 0 - Success, negative - Failure
@@ -289,7 +288,7 @@ err_init_rxq:
}
/**
- * free_txqs - Free the Logical Rx Queues of specific NIC device
+ * free_rxqs - Free the Logical Rx Queues of specific NIC device
* @nic_dev: the specific NIC device
**/
static void free_rxqs(struct hinic_dev *nic_dev)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c
index eb97f2d6b1ad..28ae6f1201a8 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c
@@ -128,7 +128,7 @@ int hinic_port_get_mac(struct hinic_dev *nic_dev, u8 *addr)
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_MAC,
&port_mac_cmd, sizeof(port_mac_cmd),
&port_mac_cmd, &out_size);
- if (err || (out_size != sizeof(port_mac_cmd)) || port_mac_cmd.status) {
+ if (err || out_size != sizeof(port_mac_cmd) || port_mac_cmd.status) {
dev_err(&pdev->dev, "Failed to get mac, err: %d, status: 0x%x, out size: 0x%x\n",
err, port_mac_cmd.status, out_size);
return -EFAULT;
@@ -263,7 +263,7 @@ int hinic_port_link_state(struct hinic_dev *nic_dev,
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_LINK_STATE,
&link_cmd, sizeof(link_cmd),
&link_cmd, &out_size);
- if (err || (out_size != sizeof(link_cmd)) || link_cmd.status) {
+ if (err || out_size != sizeof(link_cmd) || link_cmd.status) {
dev_err(&pdev->dev, "Failed to get link state, err: %d, status: 0x%x, out size: 0x%x\n",
err, link_cmd.status, out_size);
return -EINVAL;
@@ -297,7 +297,7 @@ int hinic_port_set_state(struct hinic_dev *nic_dev, enum hinic_port_state state)
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_PORT_STATE,
&port_state, sizeof(port_state),
&port_state, &out_size);
- if (err || (out_size != sizeof(port_state)) || port_state.status) {
+ if (err || out_size != sizeof(port_state) || port_state.status) {
dev_err(&pdev->dev, "Failed to set port state, err: %d, status: 0x%x, out size: 0x%x\n",
err, port_state.status, out_size);
return -EFAULT;
@@ -329,7 +329,7 @@ int hinic_port_set_func_state(struct hinic_dev *nic_dev,
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_FUNC_STATE,
&func_state, sizeof(func_state),
&func_state, &out_size);
- if (err || (out_size != sizeof(func_state)) || func_state.status) {
+ if (err || out_size != sizeof(func_state) || func_state.status) {
dev_err(&pdev->dev, "Failed to set port func state, err: %d, status: 0x%x, out size: 0x%x\n",
err, func_state.status, out_size);
return -EFAULT;
@@ -359,7 +359,7 @@ int hinic_port_get_cap(struct hinic_dev *nic_dev,
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_CAP,
port_cap, sizeof(*port_cap),
port_cap, &out_size);
- if (err || (out_size != sizeof(*port_cap)) || port_cap->status) {
+ if (err || out_size != sizeof(*port_cap) || port_cap->status) {
dev_err(&pdev->dev,
"Failed to get port capabilities, err: %d, status: 0x%x, out size: 0x%x\n",
err, port_cap->status, out_size);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c b/drivers/net/ethernet/huawei/hinic/hinic_rx.c
index cce08647b9b2..fed3b6bc0d76 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c
@@ -118,6 +118,7 @@ static void rx_csum(struct hinic_rxq *rxq, u32 status,
skb->ip_summed = CHECKSUM_NONE;
}
}
+
/**
* rx_alloc_skb - allocate skb and map it to dma address
* @rxq: rx queue
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
index 710c4ff7bc0e..c5bdb0d374ef 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
@@ -660,7 +660,7 @@ static void tx_free_skb(struct hinic_dev *nic_dev, struct sk_buff *skb,
}
/**
- * free_all_rx_skbs - free all skbs in tx queue
+ * free_all_tx_skbs - free all skbs in tx queue
* @txq: tx queue
**/
static void free_all_tx_skbs(struct hinic_txq *txq)
@@ -717,7 +717,7 @@ static int free_tx_poll(struct napi_struct *napi, int budget)
/* Reading a WQEBB to get real WQE size and consumer index. */
sq_wqe = hinic_sq_read_wqebb(sq, &skb, &wqe_size, &sw_ci);
- if ((!sq_wqe) ||
+ if (!sq_wqe ||
(((hw_ci - sw_ci) & wq->mask) * wq->wqebb_size < wqe_size))
break;
diff --git a/drivers/net/ethernet/ibm/emac/emac.h b/drivers/net/ethernet/ibm/emac/emac.h
index aa9f651288d5..09d3ac374b2d 100644
--- a/drivers/net/ethernet/ibm/emac/emac.h
+++ b/drivers/net/ethernet/ibm/emac/emac.h
@@ -77,7 +77,7 @@ struct emac_regs {
struct {
u32 rsvd1;
u32 revid;
- u32 rsvd2[2];
+ u32 rsvd2[2];
u32 iaht1; /* Reset, R */
u32 iaht2; /* Reset, R */
u32 iaht3; /* Reset, R */
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 7fea9ae60f13..bc67a7ee872b 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1799,8 +1799,7 @@ static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr,
struct ibmveth_buff_pool *pool = container_of(kobj,
struct ibmveth_buff_pool,
kobj);
- struct net_device *netdev = dev_get_drvdata(
- container_of(kobj->parent, struct device, kobj));
+ struct net_device *netdev = dev_get_drvdata(kobj_to_dev(kobj->parent));
struct ibmveth_adapter *adapter = netdev_priv(netdev);
long value = simple_strtol(buf, NULL, 10);
long rc;
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 19cf36360933..1042e79a1397 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -2522,7 +2522,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
* turn it on. For compatibility with a TBI link
* partner, we will store bad packets. Some
* frames have an additional byte on the end and
- * will look like CRC errors to to the hardware.
+ * will look like CRC errors to the hardware.
*/
if (!hw->tbi_compatibility_on) {
hw->tbi_compatibility_on = true;
@@ -2723,7 +2723,7 @@ static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, u32 data, u16 count)
* e1000_shift_in_mdi_bits - Shifts data bits in from the PHY
* @hw: Struct containing variables accessed by shared code
*
- * Bits are shifted in in MSB to LSB order.
+ * Bits are shifted in MSB to LSB order.
*/
static u16 e1000_shift_in_mdi_bits(struct e1000_hw *hw)
{
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 042de276e632..c2a109126c27 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -5245,7 +5245,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags))
pci_disable_device(pdev);
- /* Request a slot slot reset. */
+ /* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
}
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 590ad110d383..cf7b3887da1d 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -4639,7 +4639,7 @@ static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
* @hw: pointer to the HW structure
*
* ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
- * register, so the the bus width is hard coded.
+ * register, so the bus width is hard coded.
**/
static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
{
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 88e9035b75cf..5435606149b0 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -7118,7 +7118,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
pci_disable_device(pdev);
- /* Request a slot slot reset. */
+ /* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
}
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 1db35b2c7750..0f0efee5fc8e 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -2978,7 +2978,7 @@ static u32 e1000_get_phy_addr_for_hv_page(u32 page)
* @data: pointer to the data to be read or written
* @read: determines if operation is read or write
*
- * Reads the PHY register at offset and stores the retreived information
+ * Reads the PHY register at offset and stores the retrieved information
* in data. Assumes semaphore already acquired. Note that the procedure
* to access these regs uses the address port and data port to read/write.
* These accesses done with PHY address 2 and without using pages.
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 069471b7ffb0..92c0701e2a36 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -2151,12 +2151,9 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
}
if (!skb) {
- xdp.data = pktbuf + pkt_offset;
- xdp.data_end = xdp.data + size;
- xdp.data_hard_start = pktbuf - igc_rx_offset(rx_ring);
- xdp_set_data_meta_invalid(&xdp);
- xdp.frame_sz = truesize;
- xdp.rxq = &rx_ring->xdp_rxq;
+ xdp_init_buff(&xdp, truesize, &rx_ring->xdp_rxq);
+ xdp_prepare_buff(&xdp, pktbuf - igc_rx_offset(rx_ring),
+ igc_rx_offset(rx_ring) + pkt_offset, size, false);
skb = igc_xdp_run_prog(adapter, &xdp);
}
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index ec706d614cac..b2259bf1d299 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3784,9 +3784,9 @@ mvpp2_xdp_xmit(struct net_device *dev, int num_frame,
}
static int
-mvpp2_run_xdp(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq,
- struct bpf_prog *prog, struct xdp_buff *xdp,
- struct page_pool *pp, struct mvpp2_pcpu_stats *stats)
+mvpp2_run_xdp(struct mvpp2_port *port, struct bpf_prog *prog,
+ struct xdp_buff *xdp, struct page_pool *pp,
+ struct mvpp2_pcpu_stats *stats)
{
unsigned int len, sync, err;
struct page *page;
@@ -3925,7 +3925,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM,
rx_bytes, false);
- ret = mvpp2_run_xdp(port, rxq, xdp_prog, &xdp, pp, &ps);
+ ret = mvpp2_run_xdp(port, xdp_prog, &xdp, pp, &ps);
if (ret) {
xdp_ret |= ret;
@@ -7311,7 +7311,6 @@ static int mvpp2_get_sram(struct platform_device *pdev,
static int mvpp2_probe(struct platform_device *pdev)
{
- const struct acpi_device_id *acpi_id;
struct fwnode_handle *fwnode = pdev->dev.fwnode;
struct fwnode_handle *port_fwnode;
struct mvpp2 *priv;
@@ -7324,16 +7323,7 @@ static int mvpp2_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- if (has_acpi_companion(&pdev->dev)) {
- acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
- &pdev->dev);
- if (!acpi_id)
- return -EINVAL;
- priv->hw_version = (unsigned long)acpi_id->driver_data;
- } else {
- priv->hw_version =
- (unsigned long)of_device_get_match_data(&pdev->dev);
- }
+ priv->hw_version = (unsigned long)device_get_match_data(&pdev->dev);
/* multi queue mode isn't supported on PPV2.1, fallback to single
* mode
@@ -7445,34 +7435,35 @@ static int mvpp2_probe(struct platform_device *pdev)
if (err < 0)
goto err_gop_clk;
- priv->mg_core_clk = devm_clk_get(&pdev->dev, "mg_core_clk");
+ priv->mg_core_clk = devm_clk_get_optional(&pdev->dev, "mg_core_clk");
if (IS_ERR(priv->mg_core_clk)) {
- priv->mg_core_clk = NULL;
- } else {
- err = clk_prepare_enable(priv->mg_core_clk);
- if (err < 0)
- goto err_mg_clk;
+ err = PTR_ERR(priv->mg_core_clk);
+ goto err_mg_clk;
}
+
+ err = clk_prepare_enable(priv->mg_core_clk);
+ if (err < 0)
+ goto err_mg_clk;
}
- priv->axi_clk = devm_clk_get(&pdev->dev, "axi_clk");
+ priv->axi_clk = devm_clk_get_optional(&pdev->dev, "axi_clk");
if (IS_ERR(priv->axi_clk)) {
err = PTR_ERR(priv->axi_clk);
- if (err == -EPROBE_DEFER)
- goto err_mg_core_clk;
- priv->axi_clk = NULL;
- } else {
- err = clk_prepare_enable(priv->axi_clk);
- if (err < 0)
- goto err_mg_core_clk;
+ goto err_mg_core_clk;
}
+ err = clk_prepare_enable(priv->axi_clk);
+ if (err < 0)
+ goto err_mg_core_clk;
+
/* Get system's tclk rate */
priv->tclk = clk_get_rate(priv->pp_clk);
- } else if (device_property_read_u32(&pdev->dev, "clock-frequency",
- &priv->tclk)) {
- dev_err(&pdev->dev, "missing clock-frequency value\n");
- return -EINVAL;
+ } else {
+ err = device_property_read_u32(&pdev->dev, "clock-frequency", &priv->tclk);
+ if (err) {
+ dev_err(&pdev->dev, "missing clock-frequency value\n");
+ return err;
+ }
}
if (priv->hw_version >= MVPP22) {
@@ -7552,6 +7543,8 @@ static int mvpp2_probe(struct platform_device *pdev)
return 0;
err_port_probe:
+ fwnode_handle_put(port_fwnode);
+
i = 0;
fwnode_for_each_available_child_node(fwnode, port_fwnode) {
if (priv->port_list[i])
@@ -7560,13 +7553,10 @@ err_port_probe:
}
err_axi_clk:
clk_disable_unprepare(priv->axi_clk);
-
err_mg_core_clk:
- if (priv->hw_version >= MVPP22)
- clk_disable_unprepare(priv->mg_core_clk);
+ clk_disable_unprepare(priv->mg_core_clk);
err_mg_clk:
- if (priv->hw_version >= MVPP22)
- clk_disable_unprepare(priv->mg_clk);
+ clk_disable_unprepare(priv->mg_clk);
err_gop_clk:
clk_disable_unprepare(priv->gop_clk);
err_pp_clk:
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
index 7cc7d72d761e..93575800ca92 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
@@ -394,9 +394,6 @@ static int mvpp2_prs_tcam_first_free(struct mvpp2 *priv, unsigned char start,
if (start > end)
swap(start, end);
- if (end >= MVPP2_PRS_TCAM_SRAM_SIZE)
- end = MVPP2_PRS_TCAM_SRAM_SIZE - 1;
-
for (tid = start; tid <= end; tid++) {
if (!priv->prs_shadow[tid].valid)
return tid;
diff --git a/drivers/net/ethernet/marvell/skge.h b/drivers/net/ethernet/marvell/skge.h
index 6928abcec0a3..f72217348eb4 100644
--- a/drivers/net/ethernet/marvell/skge.h
+++ b/drivers/net/ethernet/marvell/skge.h
@@ -263,7 +263,7 @@ enum {
CHIP_ID_YUKON_LP = 0xb2, /* Chip ID for YUKON-LP */
CHIP_ID_YUKON_XL = 0xb3, /* Chip ID for YUKON-2 XL */
CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */
- CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
+ CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
CHIP_REV_YU_LITE_A1 = 3, /* Chip Rev. for YUKON-Lite A1,A2 */
CHIP_REV_YU_LITE_A3 = 7, /* Chip Rev. for YUKON-Lite A3 */
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 222c32367b2c..324c280cc22c 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -471,7 +471,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
adv |= fiber_fc_adv[sky2->flow_mode];
} else {
reg |= GM_GPCR_AU_FCT_DIS;
- reg |= gm_fc_disable[sky2->flow_mode];
+ reg |= gm_fc_disable[sky2->flow_mode];
/* Forward pause packets to GMAC? */
if (sky2->flow_mode & FC_RX)
@@ -1656,16 +1656,16 @@ static void sky2_hw_up(struct sky2_port *sky2)
tx_init(sky2);
/*
- * On dual port PCI-X card, there is an problem where status
+ * On dual port PCI-X card, there is an problem where status
* can be received out of order due to split transactions
*/
if (otherdev && netif_running(otherdev) &&
- (cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PCIX))) {
- u16 cmd;
+ (cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PCIX))) {
+ u16 cmd;
cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
- cmd &= ~PCI_X_CMD_MAX_SPLIT;
- sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
+ cmd &= ~PCI_X_CMD_MAX_SPLIT;
+ sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
}
sky2_mac_init(hw, port);
@@ -1836,8 +1836,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
u16 mss;
u8 ctrl;
- if (unlikely(tx_avail(sky2) < tx_le_req(skb)))
- return NETDEV_TX_BUSY;
+ if (unlikely(tx_avail(sky2) < tx_le_req(skb)))
+ return NETDEV_TX_BUSY;
len = skb_headlen(skb);
mapping = dma_map_single(&hw->pdev->dev, skb->data, len,
@@ -1866,9 +1866,9 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
if (!(hw->flags & SKY2_HW_NEW_LE))
mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
- if (mss != sky2->tx_last_mss) {
+ if (mss != sky2->tx_last_mss) {
le = get_tx_le(sky2, &slot);
- le->addr = cpu_to_le32(mss);
+ le->addr = cpu_to_le32(mss);
if (hw->flags & SKY2_HW_NEW_LE)
le->opcode = OP_MSS | HW_OWNER;
@@ -1895,8 +1895,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
/* Handle TCP checksum offload */
if (skb->ip_summed == CHECKSUM_PARTIAL) {
/* On Yukon EX (some versions) encoding change. */
- if (hw->flags & SKY2_HW_AUTO_TX_SUM)
- ctrl |= CALSUM; /* auto checksum */
+ if (hw->flags & SKY2_HW_AUTO_TX_SUM)
+ ctrl |= CALSUM; /* auto checksum */
else {
const unsigned offset = skb_transport_offset(skb);
u32 tcpsum;
@@ -2557,7 +2557,7 @@ nobuf:
static struct sk_buff *sky2_receive(struct net_device *dev,
u16 length, u32 status)
{
- struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_port *sky2 = netdev_priv(dev);
struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
struct sk_buff *skb = NULL;
u16 count = (status & GMR_FS_LEN) >> 16;
@@ -5063,11 +5063,11 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!disable_msi && pci_enable_msi(pdev) == 0) {
err = sky2_test_msi(hw);
if (err) {
- pci_disable_msi(pdev);
+ pci_disable_msi(pdev);
if (err != -EOPNOTSUPP)
goto err_out_free_netdev;
}
- }
+ }
netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h
index b2dddd8a246c..ddec1627f1a7 100644
--- a/drivers/net/ethernet/marvell/sky2.h
+++ b/drivers/net/ethernet/marvell/sky2.h
@@ -538,8 +538,8 @@ enum {
CHIP_ID_YUKON_EC_U = 0xb4, /* YUKON-2 EC Ultra */
CHIP_ID_YUKON_EX = 0xb5, /* YUKON-2 Extreme */
CHIP_ID_YUKON_EC = 0xb6, /* YUKON-2 EC */
- CHIP_ID_YUKON_FE = 0xb7, /* YUKON-2 FE */
- CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */
+ CHIP_ID_YUKON_FE = 0xb7, /* YUKON-2 FE */
+ CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */
CHIP_ID_YUKON_SUPR = 0xb9, /* YUKON-2 Supreme */
CHIP_ID_YUKON_UL_2 = 0xba, /* YUKON-2 Ultra 2 */
CHIP_ID_YUKON_OPT = 0xbc, /* YUKON-2 Optima */
@@ -2262,8 +2262,8 @@ struct sky2_port {
#define SKY2_FLAG_AUTO_SPEED 0x0002
#define SKY2_FLAG_AUTO_PAUSE 0x0004
- enum flow_control flow_mode;
- enum flow_control flow_status;
+ enum flow_control flow_mode;
+ enum flow_control flow_status;
#ifdef CONFIG_SKY2_DEBUG
struct dentry *debugfs;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
index a619d90559f7..12871c8dc7c1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
@@ -49,28 +49,6 @@ config MLXSW_I2C
To compile this driver as a module, choose M here: the
module will be called mlxsw_i2c.
-config MLXSW_SWITCHIB
- tristate "Mellanox Technologies SwitchIB and SwitchIB-2 support"
- depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV
- default m
- help
- This driver supports Mellanox Technologies SwitchIB and SwitchIB-2
- Infiniband Switch ASICs.
-
- To compile this driver as a module, choose M here: the
- module will be called mlxsw_switchib.
-
-config MLXSW_SWITCHX2
- tristate "Mellanox Technologies SwitchX-2 support"
- depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV
- default m
- help
- This driver supports Mellanox Technologies SwitchX-2 Ethernet
- Switch ASICs.
-
- To compile this driver as a module, choose M here: the
- module will be called mlxsw_switchx2.
-
config MLXSW_SPECTRUM
tristate "Mellanox Technologies Spectrum family support"
depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV && VLAN_8021Q
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile
index f545fd2c5896..196adeb33495 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile
@@ -8,10 +8,6 @@ obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o
mlxsw_pci-objs := pci.o
obj-$(CONFIG_MLXSW_I2C) += mlxsw_i2c.o
mlxsw_i2c-objs := i2c.o
-obj-$(CONFIG_MLXSW_SWITCHIB) += mlxsw_switchib.o
-mlxsw_switchib-objs := switchib.o
-obj-$(CONFIG_MLXSW_SWITCHX2) += mlxsw_switchx2.o
-mlxsw_switchx2-objs := switchx2.o
obj-$(CONFIG_MLXSW_SPECTRUM) += mlxsw_spectrum.o
mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_switchdev.o spectrum_router.o \
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index 7e9a7cb31720..ad93e01b2cda 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -630,7 +630,7 @@ static int mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core,
struct sk_buff *skb;
int err;
- skb = skb_copy(trans->tx_skb, GFP_KERNEL);
+ skb = skb_clone(trans->tx_skb, GFP_KERNEL);
if (!skb)
return -ENOMEM;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/ib.h b/drivers/net/ethernet/mellanox/mlxsw/ib.h
deleted file mode 100644
index 2d0cb0f5eb85..000000000000
--- a/drivers/net/ethernet/mellanox/mlxsw/ib.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
-/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
-
-#ifndef _MLXSW_IB_H
-#define _MLXSW_IB_H
-
-#define MLXSW_IB_DEFAULT_MTU 4096
-
-#endif /* _MLXSW_IB_H */
diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
index b34c44723f8b..68102726c6a7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
@@ -234,6 +234,7 @@ static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port)
static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
u8 *last_module)
{
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
u8 module, width;
int err;
@@ -249,6 +250,9 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
if (module == *last_module)
return 0;
*last_module = module;
+
+ if (WARN_ON_ONCE(module >= max_ports))
+ return -EINVAL;
mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports;
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index 8e8456811384..13b0259f7ea6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -1426,11 +1426,6 @@ static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci,
unsigned long end;
u32 val;
- if (id->device == PCI_DEVICE_ID_MELLANOX_SWITCHX2) {
- msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
- return 0;
- }
-
/* We must wait for the HW to become responsive. */
msleep(MLXSW_PCI_SW_RESET_WAIT_MSECS);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.h b/drivers/net/ethernet/mellanox/mlxsw/pci.h
index 5b1323645a5d..9899c1a2ea8f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.h
@@ -6,12 +6,9 @@
#include <linux/pci.h>
-#define PCI_DEVICE_ID_MELLANOX_SWITCHX2 0xc738
#define PCI_DEVICE_ID_MELLANOX_SPECTRUM 0xcb84
#define PCI_DEVICE_ID_MELLANOX_SPECTRUM2 0xcf6c
#define PCI_DEVICE_ID_MELLANOX_SPECTRUM3 0xcf70
-#define PCI_DEVICE_ID_MELLANOX_SWITCHIB 0xcb20
-#define PCI_DEVICE_ID_MELLANOX_SWITCHIB2 0xcf08
#if IS_ENABLED(CONFIG_MLXSW_PCI)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 900b4bf5bb5b..f9419cc53480 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -8305,6 +8305,8 @@ enum {
MLXSW_REG_RECR2_TCP_UDP_EN_IPV4 = 7,
/* Enable TCP/UDP header fields if packet is IPv6 */
MLXSW_REG_RECR2_TCP_UDP_EN_IPV6 = 8,
+
+ __MLXSW_REG_RECR2_HEADER_CNT,
};
/* reg_recr2_outer_header_enables
@@ -8339,6 +8341,8 @@ enum {
MLXSW_REG_RECR2_TCP_UDP_SPORT = 74,
/* TCP/UDP Destination Port */
MLXSW_REG_RECR2_TCP_UDP_DPORT = 75,
+
+ __MLXSW_REG_RECR2_FIELD_CNT,
};
/* reg_recr2_outer_header_fields_enable
@@ -8347,47 +8351,47 @@ enum {
*/
MLXSW_ITEM_BIT_ARRAY(reg, recr2, outer_header_fields_enable, 0x14, 0x14, 1);
-static inline void mlxsw_reg_recr2_ipv4_sip_enable(char *payload)
-{
- int i;
-
- for (i = MLXSW_REG_RECR2_IPV4_SIP0; i <= MLXSW_REG_RECR2_IPV4_SIP3; i++)
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
- true);
-}
-
-static inline void mlxsw_reg_recr2_ipv4_dip_enable(char *payload)
-{
- int i;
-
- for (i = MLXSW_REG_RECR2_IPV4_DIP0; i <= MLXSW_REG_RECR2_IPV4_DIP3; i++)
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
- true);
-}
-
-static inline void mlxsw_reg_recr2_ipv6_sip_enable(char *payload)
-{
- int i = MLXSW_REG_RECR2_IPV6_SIP0_7;
-
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, true);
-
- i = MLXSW_REG_RECR2_IPV6_SIP8;
- for (; i <= MLXSW_REG_RECR2_IPV6_SIP15; i++)
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
- true);
-}
-
-static inline void mlxsw_reg_recr2_ipv6_dip_enable(char *payload)
-{
- int i = MLXSW_REG_RECR2_IPV6_DIP0_7;
-
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, true);
+/* reg_recr2_inner_header_enables
+ * Bit mask where each bit enables a specific inner layer to be included in the
+ * hash calculation. Same values as reg_recr2_outer_header_enables.
+ * Access: RW
+ */
+MLXSW_ITEM_BIT_ARRAY(reg, recr2, inner_header_enables, 0x2C, 0x04, 1);
- i = MLXSW_REG_RECR2_IPV6_DIP8;
- for (; i <= MLXSW_REG_RECR2_IPV6_DIP15; i++)
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
- true);
-}
+enum {
+ /* Inner IPv4 Source IP */
+ MLXSW_REG_RECR2_INNER_IPV4_SIP0 = 3,
+ MLXSW_REG_RECR2_INNER_IPV4_SIP3 = 6,
+ /* Inner IPv4 Destination IP */
+ MLXSW_REG_RECR2_INNER_IPV4_DIP0 = 7,
+ MLXSW_REG_RECR2_INNER_IPV4_DIP3 = 10,
+ /* Inner IP Protocol */
+ MLXSW_REG_RECR2_INNER_IPV4_PROTOCOL = 11,
+ /* Inner IPv6 Source IP */
+ MLXSW_REG_RECR2_INNER_IPV6_SIP0_7 = 12,
+ MLXSW_REG_RECR2_INNER_IPV6_SIP8 = 20,
+ MLXSW_REG_RECR2_INNER_IPV6_SIP15 = 27,
+ /* Inner IPv6 Destination IP */
+ MLXSW_REG_RECR2_INNER_IPV6_DIP0_7 = 28,
+ MLXSW_REG_RECR2_INNER_IPV6_DIP8 = 36,
+ MLXSW_REG_RECR2_INNER_IPV6_DIP15 = 43,
+ /* Inner IPv6 Next Header */
+ MLXSW_REG_RECR2_INNER_IPV6_NEXT_HEADER = 44,
+ /* Inner IPv6 Flow Label */
+ MLXSW_REG_RECR2_INNER_IPV6_FLOW_LABEL = 45,
+ /* Inner TCP/UDP Source Port */
+ MLXSW_REG_RECR2_INNER_TCP_UDP_SPORT = 46,
+ /* Inner TCP/UDP Destination Port */
+ MLXSW_REG_RECR2_INNER_TCP_UDP_DPORT = 47,
+
+ __MLXSW_REG_RECR2_INNER_FIELD_CNT,
+};
+
+/* reg_recr2_inner_header_fields_enable
+ * Inner packet fields to enable for ECMP hash subject to inner_header_enables.
+ * Access: RW
+ */
+MLXSW_ITEM_BIT_ARRAY(reg, recr2, inner_header_fields_enable, 0x30, 0x08, 1);
static inline void mlxsw_reg_recr2_pack(char *payload, u32 seed)
{
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index bca0354482cb..88699e678544 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -2125,9 +2125,14 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_port *mlxsw_sp_port;
enum mlxsw_reg_pude_oper_status status;
+ unsigned int max_ports;
u8 local_port;
+ max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
local_port = mlxsw_reg_pude_local_port_get(pude_pl);
+
+ if (WARN_ON_ONCE(local_port >= max_ports))
+ return;
mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (!mlxsw_sp_port)
return;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
index 37ff29a1686e..9de160e740b2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
@@ -364,7 +364,7 @@ static u16 mlxsw_sp_hdroom_buf_delay_get(const struct mlxsw_sp *mlxsw_sp,
static u32 mlxsw_sp_hdroom_int_buf_size_get(struct mlxsw_sp *mlxsw_sp, int mtu, u32 speed)
{
- u32 buffsize = mlxsw_sp->sb_ops->int_buf_size_get(speed, mtu);
+ u32 buffsize = mlxsw_sp->sb_ops->int_buf_size_get(mtu, speed);
return mlxsw_sp_bytes_cells(mlxsw_sp, buffsize) + 1;
}
@@ -388,8 +388,8 @@ void mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port *mlxsw_sp_port,
int i;
/* Internal buffer. */
- reserve_cells = mlxsw_sp_hdroom_int_buf_size_get(mlxsw_sp, mlxsw_sp_port->max_speed,
- mlxsw_sp_port->max_mtu);
+ reserve_cells = mlxsw_sp_hdroom_int_buf_size_get(mlxsw_sp, mlxsw_sp_port->max_mtu,
+ mlxsw_sp_port->max_speed);
reserve_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, reserve_cells);
hdroom->int_buf.reserve_cells = reserve_cells;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
index d6e9ecb14681..bfef65d1587c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
@@ -568,10 +568,13 @@ void mlxsw_sp1_ptp_got_timestamp(struct mlxsw_sp *mlxsw_sp, bool ingress,
u8 domain_number, u16 sequence_id,
u64 timestamp)
{
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
struct mlxsw_sp_port *mlxsw_sp_port;
struct mlxsw_sp1_ptp_key key;
u8 types;
+ if (WARN_ON_ONCE(local_port >= max_ports))
+ return;
mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (!mlxsw_sp_port)
return;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 41259c0004d1..6decc5a43f98 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -2282,6 +2282,7 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
char *rauhtd_pl,
int ent_index)
{
+ u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
struct net_device *dev;
struct neighbour *n;
__be32 dipn;
@@ -2290,6 +2291,8 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
+ if (WARN_ON_ONCE(rif >= max_rifs))
+ return;
if (!mlxsw_sp->router->rifs[rif]) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
return;
@@ -3841,8 +3844,8 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
bool offload_change = false;
u32 adj_index;
bool old_adj_index_valid;
- int i, err2, err = 0;
u32 old_adj_index;
+ int i, err2, err;
if (!nhgi->gateway)
return mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
@@ -3872,11 +3875,13 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
return 0;
}
mlxsw_sp_nexthop_group_normalize(nhgi);
- if (!nhgi->sum_norm_weight)
+ if (!nhgi->sum_norm_weight) {
/* No neigh of this group is connected so we just set
* the trap and let everthing flow through kernel.
*/
+ err = 0;
goto set_trap;
+ }
ecmp_size = nhgi->sum_norm_weight;
err = mlxsw_sp_fix_adj_grp_size(mlxsw_sp, &ecmp_size);
@@ -9594,66 +9599,229 @@ static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
-static void mlxsw_sp_mp_hash_header_set(char *recr2_pl, int header)
+struct mlxsw_sp_mp_hash_config {
+ DECLARE_BITMAP(headers, __MLXSW_REG_RECR2_HEADER_CNT);
+ DECLARE_BITMAP(fields, __MLXSW_REG_RECR2_FIELD_CNT);
+ DECLARE_BITMAP(inner_headers, __MLXSW_REG_RECR2_HEADER_CNT);
+ DECLARE_BITMAP(inner_fields, __MLXSW_REG_RECR2_INNER_FIELD_CNT);
+};
+
+#define MLXSW_SP_MP_HASH_HEADER_SET(_headers, _header) \
+ bitmap_set(_headers, MLXSW_REG_RECR2_##_header, 1)
+
+#define MLXSW_SP_MP_HASH_FIELD_SET(_fields, _field) \
+ bitmap_set(_fields, MLXSW_REG_RECR2_##_field, 1)
+
+#define MLXSW_SP_MP_HASH_FIELD_RANGE_SET(_fields, _field, _nr) \
+ bitmap_set(_fields, MLXSW_REG_RECR2_##_field, _nr)
+
+static void mlxsw_sp_mp_hash_inner_l3(struct mlxsw_sp_mp_hash_config *config)
{
- mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, header, true);
+ unsigned long *inner_headers = config->inner_headers;
+ unsigned long *inner_fields = config->inner_fields;
+
+ /* IPv4 inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_SIP0, 4);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_DIP0, 4);
+ /* IPv6 inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_SIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_SIP8, 8);
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_DIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_DIP8, 8);
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_NEXT_HEADER);
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_FLOW_LABEL);
}
-static void mlxsw_sp_mp_hash_field_set(char *recr2_pl, int field)
+static void mlxsw_sp_mp4_hash_outer_addr(struct mlxsw_sp_mp_hash_config *config)
{
- mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true);
+ unsigned long *headers = config->headers;
+ unsigned long *fields = config->fields;
+
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_SIP0, 4);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_DIP0, 4);
}
-static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl)
+static void
+mlxsw_sp_mp_hash_inner_custom(struct mlxsw_sp_mp_hash_config *config,
+ u32 hash_fields)
+{
+ unsigned long *inner_headers = config->inner_headers;
+ unsigned long *inner_fields = config->inner_fields;
+
+ /* IPv4 Inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_TCP_UDP);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP)
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_SIP0, 4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP)
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_DIP0, 4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV4_PROTOCOL);
+ /* IPv6 inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_TCP_UDP);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP) {
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_SIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_SIP8, 8);
+ }
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP) {
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_DIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_DIP8, 8);
+ }
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_NEXT_HEADER);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_FLOWLABEL)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_FLOW_LABEL);
+ /* L4 inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, TCP_UDP_EN_IPV4);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, TCP_UDP_EN_IPV6);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_TCP_UDP_SPORT);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_TCP_UDP_DPORT);
+}
+
+static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_mp_hash_config *config)
{
struct net *net = mlxsw_sp_net(mlxsw_sp);
- bool only_l3 = !net->ipv4.sysctl_fib_multipath_hash_policy;
-
- mlxsw_sp_mp_hash_header_set(recr2_pl,
- MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP);
- mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_TCP_UDP);
- mlxsw_reg_recr2_ipv4_sip_enable(recr2_pl);
- mlxsw_reg_recr2_ipv4_dip_enable(recr2_pl);
- if (only_l3)
- return;
- mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_EN_IPV4);
- mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV4_PROTOCOL);
- mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_SPORT);
- mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT);
+ unsigned long *headers = config->headers;
+ unsigned long *fields = config->fields;
+ u32 hash_fields;
+
+ switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
+ case 0:
+ mlxsw_sp_mp4_hash_outer_addr(config);
+ break;
+ case 1:
+ mlxsw_sp_mp4_hash_outer_addr(config);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV4);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV4_PROTOCOL);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
+ break;
+ case 2:
+ /* Outer */
+ mlxsw_sp_mp4_hash_outer_addr(config);
+ /* Inner */
+ mlxsw_sp_mp_hash_inner_l3(config);
+ break;
+ case 3:
+ hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+ /* Outer */
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP)
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_SIP0, 4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP)
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_DIP0, 4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV4_PROTOCOL);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
+ /* Inner */
+ mlxsw_sp_mp_hash_inner_custom(config, hash_fields);
+ break;
+ }
}
-static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl)
+static void mlxsw_sp_mp6_hash_outer_addr(struct mlxsw_sp_mp_hash_config *config)
{
- bool only_l3 = !ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp));
+ unsigned long *headers = config->headers;
+ unsigned long *fields = config->fields;
- mlxsw_sp_mp_hash_header_set(recr2_pl,
- MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP);
- mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_TCP_UDP);
- mlxsw_reg_recr2_ipv6_sip_enable(recr2_pl);
- mlxsw_reg_recr2_ipv6_dip_enable(recr2_pl);
- mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV6_NEXT_HEADER);
- if (only_l3) {
- mlxsw_sp_mp_hash_field_set(recr2_pl,
- MLXSW_REG_RECR2_IPV6_FLOW_LABEL);
- } else {
- mlxsw_sp_mp_hash_header_set(recr2_pl,
- MLXSW_REG_RECR2_TCP_UDP_EN_IPV6);
- mlxsw_sp_mp_hash_field_set(recr2_pl,
- MLXSW_REG_RECR2_TCP_UDP_SPORT);
- mlxsw_sp_mp_hash_field_set(recr2_pl,
- MLXSW_REG_RECR2_TCP_UDP_DPORT);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_SIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_SIP8, 8);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_DIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_DIP8, 8);
+}
+
+static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_mp_hash_config *config)
+{
+ u32 hash_fields = ip6_multipath_hash_fields(mlxsw_sp_net(mlxsw_sp));
+ unsigned long *headers = config->headers;
+ unsigned long *fields = config->fields;
+
+ switch (ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp))) {
+ case 0:
+ mlxsw_sp_mp6_hash_outer_addr(config);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
+ break;
+ case 1:
+ mlxsw_sp_mp6_hash_outer_addr(config);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV6);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
+ break;
+ case 2:
+ /* Outer */
+ mlxsw_sp_mp6_hash_outer_addr(config);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
+ /* Inner */
+ mlxsw_sp_mp_hash_inner_l3(config);
+ break;
+ case 3:
+ /* Outer */
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV6);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP) {
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_SIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_SIP8, 8);
+ }
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP) {
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_DIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_DIP8, 8);
+ }
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_FLOWLABEL)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
+ /* Inner */
+ mlxsw_sp_mp_hash_inner_custom(config, hash_fields);
+ break;
}
}
static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
{
+ struct mlxsw_sp_mp_hash_config config = {};
char recr2_pl[MLXSW_REG_RECR2_LEN];
+ unsigned long bit;
u32 seed;
seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0);
mlxsw_reg_recr2_pack(recr2_pl, seed);
- mlxsw_sp_mp4_hash_init(mlxsw_sp, recr2_pl);
- mlxsw_sp_mp6_hash_init(mlxsw_sp, recr2_pl);
+ mlxsw_sp_mp4_hash_init(mlxsw_sp, &config);
+ mlxsw_sp_mp6_hash_init(mlxsw_sp, &config);
+
+ for_each_set_bit(bit, config.headers, __MLXSW_REG_RECR2_HEADER_CNT)
+ mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, bit, 1);
+ for_each_set_bit(bit, config.fields, __MLXSW_REG_RECR2_FIELD_CNT)
+ mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, bit, 1);
+ for_each_set_bit(bit, config.inner_headers, __MLXSW_REG_RECR2_HEADER_CNT)
+ mlxsw_reg_recr2_inner_header_enables_set(recr2_pl, bit, 1);
+ for_each_set_bit(bit, config.inner_fields, __MLXSW_REG_RECR2_INNER_FIELD_CNT)
+ mlxsw_reg_recr2_inner_header_fields_enable_set(recr2_pl, bit, 1);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index eeccd586e781..0cfba2986841 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -2520,6 +2520,7 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
char *sfn_pl, int rec_index,
bool adding)
{
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
struct mlxsw_sp_bridge_device *bridge_device;
struct mlxsw_sp_bridge_port *bridge_port;
@@ -2532,6 +2533,9 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
int err;
mlxsw_reg_sfn_mac_unpack(sfn_pl, rec_index, mac, &fid, &local_port);
+
+ if (WARN_ON_ONCE(local_port >= max_ports))
+ return;
mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (!mlxsw_sp_port) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect local port in FDB notification\n");
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchib.c b/drivers/net/ethernet/mellanox/mlxsw/switchib.c
deleted file mode 100644
index 1e561132eb1e..000000000000
--- a/drivers/net/ethernet/mellanox/mlxsw/switchib.c
+++ /dev/null
@@ -1,595 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
-/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/skbuff.h>
-#include <linux/if_vlan.h>
-#include <net/switchdev.h>
-
-#include "pci.h"
-#include "core.h"
-#include "reg.h"
-#include "port.h"
-#include "trap.h"
-#include "txheader.h"
-#include "ib.h"
-
-static const char mlxsw_sib_driver_name[] = "mlxsw_switchib";
-static const char mlxsw_sib2_driver_name[] = "mlxsw_switchib2";
-
-struct mlxsw_sib_port;
-
-struct mlxsw_sib {
- struct mlxsw_sib_port **ports;
- struct mlxsw_core *core;
- const struct mlxsw_bus_info *bus_info;
- u8 hw_id[ETH_ALEN];
-};
-
-struct mlxsw_sib_port {
- struct mlxsw_sib *mlxsw_sib;
- u8 local_port;
- struct {
- u8 module;
- } mapping;
-};
-
-/* tx_v1_hdr_version
- * Tx header version.
- * Must be set to 1.
- */
-MLXSW_ITEM32(tx_v1, hdr, version, 0x00, 28, 4);
-
-/* tx_v1_hdr_ctl
- * Packet control type.
- * 0 - Ethernet control (e.g. EMADs, LACP)
- * 1 - Ethernet data
- */
-MLXSW_ITEM32(tx_v1, hdr, ctl, 0x00, 26, 2);
-
-/* tx_v1_hdr_proto
- * Packet protocol type. Must be set to 1 (Ethernet).
- */
-MLXSW_ITEM32(tx_v1, hdr, proto, 0x00, 21, 3);
-
-/* tx_v1_hdr_swid
- * Switch partition ID. Must be set to 0.
- */
-MLXSW_ITEM32(tx_v1, hdr, swid, 0x00, 12, 3);
-
-/* tx_v1_hdr_control_tclass
- * Indicates if the packet should use the control TClass and not one
- * of the data TClasses.
- */
-MLXSW_ITEM32(tx_v1, hdr, control_tclass, 0x00, 6, 1);
-
-/* tx_v1_hdr_port_mid
- * Destination local port for unicast packets.
- * Destination multicast ID for multicast packets.
- *
- * Control packets are directed to a specific egress port, while data
- * packets are transmitted through the CPU port (0) into the switch partition,
- * where forwarding rules are applied.
- */
-MLXSW_ITEM32(tx_v1, hdr, port_mid, 0x04, 16, 16);
-
-/* tx_v1_hdr_type
- * 0 - Data packets
- * 6 - Control packets
- */
-MLXSW_ITEM32(tx_v1, hdr, type, 0x0C, 0, 4);
-
-static void
-mlxsw_sib_tx_v1_hdr_construct(struct sk_buff *skb,
- const struct mlxsw_tx_info *tx_info)
-{
- char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
-
- memset(txhdr, 0, MLXSW_TXHDR_LEN);
-
- mlxsw_tx_v1_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);
- mlxsw_tx_v1_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);
- mlxsw_tx_v1_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
- mlxsw_tx_v1_hdr_swid_set(txhdr, 0);
- mlxsw_tx_v1_hdr_control_tclass_set(txhdr, 1);
- mlxsw_tx_v1_hdr_port_mid_set(txhdr, tx_info->local_port);
- mlxsw_tx_v1_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
-}
-
-static int mlxsw_sib_hw_id_get(struct mlxsw_sib *mlxsw_sib)
-{
- char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
- int err;
-
- err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(spad), spad_pl);
- if (err)
- return err;
- mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sib->hw_id);
- return 0;
-}
-
-static int
-mlxsw_sib_port_admin_status_set(struct mlxsw_sib_port *mlxsw_sib_port,
- bool is_up)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char paos_pl[MLXSW_REG_PAOS_LEN];
-
- mlxsw_reg_paos_pack(paos_pl, mlxsw_sib_port->local_port,
- is_up ? MLXSW_PORT_ADMIN_STATUS_UP :
- MLXSW_PORT_ADMIN_STATUS_DOWN);
- return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(paos), paos_pl);
-}
-
-static int mlxsw_sib_port_mtu_set(struct mlxsw_sib_port *mlxsw_sib_port,
- u16 mtu)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char pmtu_pl[MLXSW_REG_PMTU_LEN];
- int max_mtu;
- int err;
-
- mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, 0);
- err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl);
- if (err)
- return err;
- max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
-
- if (mtu > max_mtu)
- return -EINVAL;
-
- mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, mtu);
- return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl);
-}
-
-static int mlxsw_sib_port_set(struct mlxsw_sib_port *mlxsw_sib_port, u8 port)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char plib_pl[MLXSW_REG_PLIB_LEN] = {0};
- int err;
-
- mlxsw_reg_plib_local_port_set(plib_pl, mlxsw_sib_port->local_port);
- mlxsw_reg_plib_ib_port_set(plib_pl, port);
- err = mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(plib), plib_pl);
- return err;
-}
-
-static int mlxsw_sib_port_swid_set(struct mlxsw_sib_port *mlxsw_sib_port,
- u8 swid)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char pspa_pl[MLXSW_REG_PSPA_LEN];
-
- mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sib_port->local_port);
- return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pspa), pspa_pl);
-}
-
-static int mlxsw_sib_port_module_info_get(struct mlxsw_sib *mlxsw_sib,
- u8 local_port, u8 *p_module,
- u8 *p_width)
-{
- char pmlp_pl[MLXSW_REG_PMLP_LEN];
- int err;
-
- mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
- err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmlp), pmlp_pl);
- if (err)
- return err;
- *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
- *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
- return 0;
-}
-
-static int mlxsw_sib_port_speed_set(struct mlxsw_sib_port *mlxsw_sib_port,
- u16 speed, u16 width)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
-
- mlxsw_reg_ptys_ib_pack(ptys_pl, mlxsw_sib_port->local_port, speed,
- width);
- return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(ptys), ptys_pl);
-}
-
-static bool mlxsw_sib_port_created(struct mlxsw_sib *mlxsw_sib, u8 local_port)
-{
- return mlxsw_sib->ports[local_port] != NULL;
-}
-
-static int __mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port,
- u8 module, u8 width)
-{
- struct mlxsw_sib_port *mlxsw_sib_port;
- int err;
-
- mlxsw_sib_port = kzalloc(sizeof(*mlxsw_sib_port), GFP_KERNEL);
- if (!mlxsw_sib_port)
- return -ENOMEM;
- mlxsw_sib_port->mlxsw_sib = mlxsw_sib;
- mlxsw_sib_port->local_port = local_port;
- mlxsw_sib_port->mapping.module = module;
-
- err = mlxsw_sib_port_swid_set(mlxsw_sib_port, 0);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set SWID\n",
- mlxsw_sib_port->local_port);
- goto err_port_swid_set;
- }
-
- /* Expose the IB port number as it's front panel name */
- err = mlxsw_sib_port_set(mlxsw_sib_port, module + 1);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set IB port\n",
- mlxsw_sib_port->local_port);
- goto err_port_ib_set;
- }
-
- /* Supports all speeds from SDR to FDR (bitmask) and support bus width
- * of 1x, 2x and 4x (3 bits bitmask)
- */
- err = mlxsw_sib_port_speed_set(mlxsw_sib_port,
- MLXSW_REG_PTYS_IB_SPEED_EDR - 1,
- BIT(3) - 1);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set speed\n",
- mlxsw_sib_port->local_port);
- goto err_port_speed_set;
- }
-
- /* Change to the maximum MTU the device supports, the SMA will take
- * care of the active MTU
- */
- err = mlxsw_sib_port_mtu_set(mlxsw_sib_port, MLXSW_IB_DEFAULT_MTU);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set MTU\n",
- mlxsw_sib_port->local_port);
- goto err_port_mtu_set;
- }
-
- err = mlxsw_sib_port_admin_status_set(mlxsw_sib_port, true);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to change admin state to UP\n",
- mlxsw_sib_port->local_port);
- goto err_port_admin_set;
- }
-
- mlxsw_core_port_ib_set(mlxsw_sib->core, mlxsw_sib_port->local_port,
- mlxsw_sib_port);
- mlxsw_sib->ports[local_port] = mlxsw_sib_port;
- return 0;
-
-err_port_admin_set:
-err_port_mtu_set:
-err_port_speed_set:
-err_port_ib_set:
- mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT);
-err_port_swid_set:
- kfree(mlxsw_sib_port);
- return err;
-}
-
-static int mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port,
- u8 module, u8 width)
-{
- int err;
-
- err = mlxsw_core_port_init(mlxsw_sib->core, local_port,
- module + 1, false, 0, false, 0,
- mlxsw_sib->hw_id, sizeof(mlxsw_sib->hw_id));
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to init core port\n",
- local_port);
- return err;
- }
- err = __mlxsw_sib_port_create(mlxsw_sib, local_port, module, width);
- if (err)
- goto err_port_create;
-
- return 0;
-
-err_port_create:
- mlxsw_core_port_fini(mlxsw_sib->core, local_port);
- return err;
-}
-
-static void __mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port)
-{
- struct mlxsw_sib_port *mlxsw_sib_port = mlxsw_sib->ports[local_port];
-
- mlxsw_core_port_clear(mlxsw_sib->core, local_port, mlxsw_sib);
- mlxsw_sib->ports[local_port] = NULL;
- mlxsw_sib_port_admin_status_set(mlxsw_sib_port, false);
- mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT);
- kfree(mlxsw_sib_port);
-}
-
-static void mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port)
-{
- __mlxsw_sib_port_remove(mlxsw_sib, local_port);
- mlxsw_core_port_fini(mlxsw_sib->core, local_port);
-}
-
-static void mlxsw_sib_ports_remove(struct mlxsw_sib *mlxsw_sib)
-{
- int i;
-
- for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++)
- if (mlxsw_sib_port_created(mlxsw_sib, i))
- mlxsw_sib_port_remove(mlxsw_sib, i);
- kfree(mlxsw_sib->ports);
-}
-
-static int mlxsw_sib_ports_create(struct mlxsw_sib *mlxsw_sib)
-{
- size_t alloc_size;
- u8 module, width;
- int i;
- int err;
-
- alloc_size = sizeof(struct mlxsw_sib_port *) * MLXSW_PORT_MAX_IB_PORTS;
- mlxsw_sib->ports = kzalloc(alloc_size, GFP_KERNEL);
- if (!mlxsw_sib->ports)
- return -ENOMEM;
-
- for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++) {
- err = mlxsw_sib_port_module_info_get(mlxsw_sib, i, &module,
- &width);
- if (err)
- goto err_port_module_info_get;
- if (!width)
- continue;
- err = mlxsw_sib_port_create(mlxsw_sib, i, module, width);
- if (err)
- goto err_port_create;
- }
- return 0;
-
-err_port_create:
-err_port_module_info_get:
- for (i--; i >= 1; i--)
- if (mlxsw_sib_port_created(mlxsw_sib, i))
- mlxsw_sib_port_remove(mlxsw_sib, i);
- kfree(mlxsw_sib->ports);
- return err;
-}
-
-static void
-mlxsw_sib_pude_ib_event_func(struct mlxsw_sib_port *mlxsw_sib_port,
- enum mlxsw_reg_pude_oper_status status)
-{
- if (status == MLXSW_PORT_OPER_STATUS_UP)
- pr_info("ib link for port %d - up\n",
- mlxsw_sib_port->mapping.module + 1);
- else
- pr_info("ib link for port %d - down\n",
- mlxsw_sib_port->mapping.module + 1);
-}
-
-static void mlxsw_sib_pude_event_func(const struct mlxsw_reg_info *reg,
- char *pude_pl, void *priv)
-{
- struct mlxsw_sib *mlxsw_sib = priv;
- struct mlxsw_sib_port *mlxsw_sib_port;
- enum mlxsw_reg_pude_oper_status status;
- u8 local_port;
-
- local_port = mlxsw_reg_pude_local_port_get(pude_pl);
- mlxsw_sib_port = mlxsw_sib->ports[local_port];
- if (!mlxsw_sib_port) {
- dev_warn(mlxsw_sib->bus_info->dev, "Port %d: Link event received for non-existent port\n",
- local_port);
- return;
- }
-
- status = mlxsw_reg_pude_oper_status_get(pude_pl);
- mlxsw_sib_pude_ib_event_func(mlxsw_sib_port, status);
-}
-
-static const struct mlxsw_listener mlxsw_sib_listener[] = {
- MLXSW_EVENTL(mlxsw_sib_pude_event_func, PUDE, EMAD),
-};
-
-static int mlxsw_sib_taps_init(struct mlxsw_sib *mlxsw_sib)
-{
- int i;
- int err;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sib_listener); i++) {
- err = mlxsw_core_trap_register(mlxsw_sib->core,
- &mlxsw_sib_listener[i],
- mlxsw_sib);
- if (err)
- goto err_rx_listener_register;
- }
-
- return 0;
-
-err_rx_listener_register:
- for (i--; i >= 0; i--) {
- mlxsw_core_trap_unregister(mlxsw_sib->core,
- &mlxsw_sib_listener[i],
- mlxsw_sib);
- }
-
- return err;
-}
-
-static void mlxsw_sib_traps_fini(struct mlxsw_sib *mlxsw_sib)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sib_listener); i++) {
- mlxsw_core_trap_unregister(mlxsw_sib->core,
- &mlxsw_sib_listener[i], mlxsw_sib);
- }
-}
-
-static int mlxsw_sib_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
-{
- char htgt_pl[MLXSW_REG_HTGT_LEN];
-
- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD,
- MLXSW_REG_HTGT_INVALID_POLICER,
- MLXSW_REG_HTGT_DEFAULT_PRIORITY,
- MLXSW_REG_HTGT_DEFAULT_TC);
- mlxsw_reg_htgt_swid_set(htgt_pl, MLXSW_PORT_SWID_ALL_SWIDS);
- mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
- MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SIB_EMAD);
- return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
-}
-
-static int mlxsw_sib_init(struct mlxsw_core *mlxsw_core,
- const struct mlxsw_bus_info *mlxsw_bus_info,
- struct netlink_ext_ack *extack)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core);
- int err;
-
- mlxsw_sib->core = mlxsw_core;
- mlxsw_sib->bus_info = mlxsw_bus_info;
-
- err = mlxsw_sib_hw_id_get(mlxsw_sib);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Failed to get switch HW ID\n");
- return err;
- }
-
- err = mlxsw_sib_ports_create(mlxsw_sib);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Failed to create ports\n");
- return err;
- }
-
- err = mlxsw_sib_taps_init(mlxsw_sib);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Failed to set traps\n");
- goto err_traps_init_err;
- }
-
- return 0;
-
-err_traps_init_err:
- mlxsw_sib_ports_remove(mlxsw_sib);
- return err;
-}
-
-static void mlxsw_sib_fini(struct mlxsw_core *mlxsw_core)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core);
-
- mlxsw_sib_traps_fini(mlxsw_sib);
- mlxsw_sib_ports_remove(mlxsw_sib);
-}
-
-static const struct mlxsw_config_profile mlxsw_sib_config_profile = {
- .used_max_system_port = 1,
- .max_system_port = 48000,
- .used_max_ib_mc = 1,
- .max_ib_mc = 27,
- .used_max_pkey = 1,
- .max_pkey = 32,
- .swid_config = {
- {
- .used_type = 1,
- .type = MLXSW_PORT_SWID_TYPE_IB,
- }
- },
-};
-
-static struct mlxsw_driver mlxsw_sib_driver = {
- .kind = mlxsw_sib_driver_name,
- .priv_size = sizeof(struct mlxsw_sib),
- .init = mlxsw_sib_init,
- .fini = mlxsw_sib_fini,
- .basic_trap_groups_set = mlxsw_sib_basic_trap_groups_set,
- .txhdr_construct = mlxsw_sib_tx_v1_hdr_construct,
- .txhdr_len = MLXSW_TXHDR_LEN,
- .profile = &mlxsw_sib_config_profile,
-};
-
-static struct mlxsw_driver mlxsw_sib2_driver = {
- .kind = mlxsw_sib2_driver_name,
- .priv_size = sizeof(struct mlxsw_sib),
- .init = mlxsw_sib_init,
- .fini = mlxsw_sib_fini,
- .basic_trap_groups_set = mlxsw_sib_basic_trap_groups_set,
- .txhdr_construct = mlxsw_sib_tx_v1_hdr_construct,
- .txhdr_len = MLXSW_TXHDR_LEN,
- .profile = &mlxsw_sib_config_profile,
-};
-
-static const struct pci_device_id mlxsw_sib_pci_id_table[] = {
- {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB), 0},
- {0, },
-};
-
-static struct pci_driver mlxsw_sib_pci_driver = {
- .name = mlxsw_sib_driver_name,
- .id_table = mlxsw_sib_pci_id_table,
-};
-
-static const struct pci_device_id mlxsw_sib2_pci_id_table[] = {
- {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB2), 0},
- {0, },
-};
-
-static struct pci_driver mlxsw_sib2_pci_driver = {
- .name = mlxsw_sib2_driver_name,
- .id_table = mlxsw_sib2_pci_id_table,
-};
-
-static int __init mlxsw_sib_module_init(void)
-{
- int err;
-
- err = mlxsw_core_driver_register(&mlxsw_sib_driver);
- if (err)
- return err;
-
- err = mlxsw_core_driver_register(&mlxsw_sib2_driver);
- if (err)
- goto err_sib2_driver_register;
-
- err = mlxsw_pci_driver_register(&mlxsw_sib_pci_driver);
- if (err)
- goto err_sib_pci_driver_register;
-
- err = mlxsw_pci_driver_register(&mlxsw_sib2_pci_driver);
- if (err)
- goto err_sib2_pci_driver_register;
-
- return 0;
-
-err_sib2_pci_driver_register:
- mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver);
-err_sib_pci_driver_register:
- mlxsw_core_driver_unregister(&mlxsw_sib2_driver);
-err_sib2_driver_register:
- mlxsw_core_driver_unregister(&mlxsw_sib_driver);
- return err;
-}
-
-static void __exit mlxsw_sib_module_exit(void)
-{
- mlxsw_pci_driver_unregister(&mlxsw_sib2_pci_driver);
- mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver);
- mlxsw_core_driver_unregister(&mlxsw_sib2_driver);
- mlxsw_core_driver_unregister(&mlxsw_sib_driver);
-}
-
-module_init(mlxsw_sib_module_init);
-module_exit(mlxsw_sib_module_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Elad Raz <eladr@@mellanox.com>");
-MODULE_DESCRIPTION("Mellanox SwitchIB and SwitchIB-2 driver");
-MODULE_ALIAS("mlxsw_switchib2");
-MODULE_DEVICE_TABLE(pci, mlxsw_sib_pci_id_table);
-MODULE_DEVICE_TABLE(pci, mlxsw_sib2_pci_id_table);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
deleted file mode 100644
index 131b2a53d261..000000000000
--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ /dev/null
@@ -1,1691 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
-/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/skbuff.h>
-#include <linux/if_vlan.h>
-
-#include "pci.h"
-#include "core.h"
-#include "reg.h"
-#include "port.h"
-#include "trap.h"
-#include "txheader.h"
-#include "ib.h"
-
-static const char mlxsw_sx_driver_name[] = "mlxsw_switchx2";
-static const char mlxsw_sx_driver_version[] = "1.0";
-
-struct mlxsw_sx_port;
-
-struct mlxsw_sx {
- struct mlxsw_sx_port **ports;
- struct mlxsw_core *core;
- const struct mlxsw_bus_info *bus_info;
- u8 hw_id[ETH_ALEN];
-};
-
-struct mlxsw_sx_port_pcpu_stats {
- u64 rx_packets;
- u64 rx_bytes;
- u64 tx_packets;
- u64 tx_bytes;
- struct u64_stats_sync syncp;
- u32 tx_dropped;
-};
-
-struct mlxsw_sx_port {
- struct net_device *dev;
- struct mlxsw_sx_port_pcpu_stats __percpu *pcpu_stats;
- struct mlxsw_sx *mlxsw_sx;
- u8 local_port;
- struct {
- u8 module;
- } mapping;
-};
-
-/* tx_hdr_version
- * Tx header version.
- * Must be set to 0.
- */
-MLXSW_ITEM32(tx, hdr, version, 0x00, 28, 4);
-
-/* tx_hdr_ctl
- * Packet control type.
- * 0 - Ethernet control (e.g. EMADs, LACP)
- * 1 - Ethernet data
- */
-MLXSW_ITEM32(tx, hdr, ctl, 0x00, 26, 2);
-
-/* tx_hdr_proto
- * Packet protocol type. Must be set to 1 (Ethernet).
- */
-MLXSW_ITEM32(tx, hdr, proto, 0x00, 21, 3);
-
-/* tx_hdr_etclass
- * Egress TClass to be used on the egress device on the egress port.
- * The MSB is specified in the 'ctclass3' field.
- * Range is 0-15, where 15 is the highest priority.
- */
-MLXSW_ITEM32(tx, hdr, etclass, 0x00, 18, 3);
-
-/* tx_hdr_swid
- * Switch partition ID.
- */
-MLXSW_ITEM32(tx, hdr, swid, 0x00, 12, 3);
-
-/* tx_hdr_port_mid
- * Destination local port for unicast packets.
- * Destination multicast ID for multicast packets.
- *
- * Control packets are directed to a specific egress port, while data
- * packets are transmitted through the CPU port (0) into the switch partition,
- * where forwarding rules are applied.
- */
-MLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16);
-
-/* tx_hdr_ctclass3
- * See field 'etclass'.
- */
-MLXSW_ITEM32(tx, hdr, ctclass3, 0x04, 14, 1);
-
-/* tx_hdr_rdq
- * RDQ for control packets sent to remote CPU.
- * Must be set to 0x1F for EMADs, otherwise 0.
- */
-MLXSW_ITEM32(tx, hdr, rdq, 0x04, 9, 5);
-
-/* tx_hdr_cpu_sig
- * Signature control for packets going to CPU. Must be set to 0.
- */
-MLXSW_ITEM32(tx, hdr, cpu_sig, 0x04, 0, 9);
-
-/* tx_hdr_sig
- * Stacking protocl signature. Must be set to 0xE0E0.
- */
-MLXSW_ITEM32(tx, hdr, sig, 0x0C, 16, 16);
-
-/* tx_hdr_stclass
- * Stacking TClass.
- */
-MLXSW_ITEM32(tx, hdr, stclass, 0x0C, 13, 3);
-
-/* tx_hdr_emad
- * EMAD bit. Must be set for EMADs.
- */
-MLXSW_ITEM32(tx, hdr, emad, 0x0C, 5, 1);
-
-/* tx_hdr_type
- * 0 - Data packets
- * 6 - Control packets
- */
-MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4);
-
-static void mlxsw_sx_txhdr_construct(struct sk_buff *skb,
- const struct mlxsw_tx_info *tx_info)
-{
- char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
- bool is_emad = tx_info->is_emad;
-
- memset(txhdr, 0, MLXSW_TXHDR_LEN);
-
- /* We currently set default values for the egress tclass (QoS). */
- mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_0);
- mlxsw_tx_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);
- mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
- mlxsw_tx_hdr_etclass_set(txhdr, is_emad ? MLXSW_TXHDR_ETCLASS_6 :
- MLXSW_TXHDR_ETCLASS_5);
- mlxsw_tx_hdr_swid_set(txhdr, 0);
- mlxsw_tx_hdr_port_mid_set(txhdr, tx_info->local_port);
- mlxsw_tx_hdr_ctclass3_set(txhdr, MLXSW_TXHDR_CTCLASS3);
- mlxsw_tx_hdr_rdq_set(txhdr, is_emad ? MLXSW_TXHDR_RDQ_EMAD :
- MLXSW_TXHDR_RDQ_OTHER);
- mlxsw_tx_hdr_cpu_sig_set(txhdr, MLXSW_TXHDR_CPU_SIG);
- mlxsw_tx_hdr_sig_set(txhdr, MLXSW_TXHDR_SIG);
- mlxsw_tx_hdr_stclass_set(txhdr, MLXSW_TXHDR_STCLASS_NONE);
- mlxsw_tx_hdr_emad_set(txhdr, is_emad ? MLXSW_TXHDR_EMAD :
- MLXSW_TXHDR_NOT_EMAD);
- mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
-}
-
-static int mlxsw_sx_port_admin_status_set(struct mlxsw_sx_port *mlxsw_sx_port,
- bool is_up)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char paos_pl[MLXSW_REG_PAOS_LEN];
-
- mlxsw_reg_paos_pack(paos_pl, mlxsw_sx_port->local_port,
- is_up ? MLXSW_PORT_ADMIN_STATUS_UP :
- MLXSW_PORT_ADMIN_STATUS_DOWN);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(paos), paos_pl);
-}
-
-static int mlxsw_sx_port_oper_status_get(struct mlxsw_sx_port *mlxsw_sx_port,
- bool *p_is_up)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char paos_pl[MLXSW_REG_PAOS_LEN];
- u8 oper_status;
- int err;
-
- mlxsw_reg_paos_pack(paos_pl, mlxsw_sx_port->local_port, 0);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(paos), paos_pl);
- if (err)
- return err;
- oper_status = mlxsw_reg_paos_oper_status_get(paos_pl);
- *p_is_up = oper_status == MLXSW_PORT_ADMIN_STATUS_UP;
- return 0;
-}
-
-static int __mlxsw_sx_port_mtu_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 mtu)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char pmtu_pl[MLXSW_REG_PMTU_LEN];
- int max_mtu;
- int err;
-
- mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sx_port->local_port, 0);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(pmtu), pmtu_pl);
- if (err)
- return err;
- max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
-
- if (mtu > max_mtu)
- return -EINVAL;
-
- mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sx_port->local_port, mtu);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pmtu), pmtu_pl);
-}
-
-static int mlxsw_sx_port_mtu_eth_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 mtu)
-{
- mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
- return __mlxsw_sx_port_mtu_set(mlxsw_sx_port, mtu);
-}
-
-static int mlxsw_sx_port_mtu_ib_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 mtu)
-{
- return __mlxsw_sx_port_mtu_set(mlxsw_sx_port, mtu);
-}
-
-static int mlxsw_sx_port_ib_port_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u8 ib_port)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char plib_pl[MLXSW_REG_PLIB_LEN] = {0};
- int err;
-
- mlxsw_reg_plib_local_port_set(plib_pl, mlxsw_sx_port->local_port);
- mlxsw_reg_plib_ib_port_set(plib_pl, ib_port);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(plib), plib_pl);
- return err;
-}
-
-static int mlxsw_sx_port_swid_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 swid)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char pspa_pl[MLXSW_REG_PSPA_LEN];
-
- mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sx_port->local_port);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pspa), pspa_pl);
-}
-
-static int
-mlxsw_sx_port_system_port_mapping_set(struct mlxsw_sx_port *mlxsw_sx_port)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char sspr_pl[MLXSW_REG_SSPR_LEN];
-
- mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sx_port->local_port);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sspr), sspr_pl);
-}
-
-static int mlxsw_sx_port_module_info_get(struct mlxsw_sx *mlxsw_sx,
- u8 local_port, u8 *p_module,
- u8 *p_width)
-{
- char pmlp_pl[MLXSW_REG_PMLP_LEN];
- int err;
-
- mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(pmlp), pmlp_pl);
- if (err)
- return err;
- *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
- *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
- return 0;
-}
-
-static int mlxsw_sx_port_open(struct net_device *dev)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- int err;
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true);
- if (err)
- return err;
- netif_start_queue(dev);
- return 0;
-}
-
-static int mlxsw_sx_port_stop(struct net_device *dev)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
-
- netif_stop_queue(dev);
- return mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
-}
-
-static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- struct mlxsw_sx_port_pcpu_stats *pcpu_stats;
- const struct mlxsw_tx_info tx_info = {
- .local_port = mlxsw_sx_port->local_port,
- .is_emad = false,
- };
- u64 len;
- int err;
-
- if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
- this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
-
- memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
-
- if (mlxsw_core_skb_transmit_busy(mlxsw_sx->core, &tx_info))
- return NETDEV_TX_BUSY;
-
- mlxsw_sx_txhdr_construct(skb, &tx_info);
- /* TX header is consumed by HW on the way so we shouldn't count its
- * bytes as being sent.
- */
- len = skb->len - MLXSW_TXHDR_LEN;
- /* Due to a race we might fail here because of a full queue. In that
- * unlikely case we simply drop the packet.
- */
- err = mlxsw_core_skb_transmit(mlxsw_sx->core, skb, &tx_info);
-
- if (!err) {
- pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats);
- u64_stats_update_begin(&pcpu_stats->syncp);
- pcpu_stats->tx_packets++;
- pcpu_stats->tx_bytes += len;
- u64_stats_update_end(&pcpu_stats->syncp);
- } else {
- this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
- dev_kfree_skb_any(skb);
- }
- return NETDEV_TX_OK;
-}
-
-static int mlxsw_sx_port_change_mtu(struct net_device *dev, int mtu)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- int err;
-
- err = mlxsw_sx_port_mtu_eth_set(mlxsw_sx_port, mtu);
- if (err)
- return err;
- dev->mtu = mtu;
- return 0;
-}
-
-static void
-mlxsw_sx_port_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *stats)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx_port_pcpu_stats *p;
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- u32 tx_dropped = 0;
- unsigned int start;
- int i;
-
- for_each_possible_cpu(i) {
- p = per_cpu_ptr(mlxsw_sx_port->pcpu_stats, i);
- do {
- start = u64_stats_fetch_begin_irq(&p->syncp);
- rx_packets = p->rx_packets;
- rx_bytes = p->rx_bytes;
- tx_packets = p->tx_packets;
- tx_bytes = p->tx_bytes;
- } while (u64_stats_fetch_retry_irq(&p->syncp, start));
-
- stats->rx_packets += rx_packets;
- stats->rx_bytes += rx_bytes;
- stats->tx_packets += tx_packets;
- stats->tx_bytes += tx_bytes;
- /* tx_dropped is u32, updated without syncp protection. */
- tx_dropped += p->tx_dropped;
- }
- stats->tx_dropped = tx_dropped;
-}
-
-static struct devlink_port *
-mlxsw_sx_port_get_devlink_port(struct net_device *dev)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
-
- return mlxsw_core_port_devlink_port_get(mlxsw_sx->core,
- mlxsw_sx_port->local_port);
-}
-
-static const struct net_device_ops mlxsw_sx_port_netdev_ops = {
- .ndo_open = mlxsw_sx_port_open,
- .ndo_stop = mlxsw_sx_port_stop,
- .ndo_start_xmit = mlxsw_sx_port_xmit,
- .ndo_change_mtu = mlxsw_sx_port_change_mtu,
- .ndo_get_stats64 = mlxsw_sx_port_get_stats64,
- .ndo_get_devlink_port = mlxsw_sx_port_get_devlink_port,
-};
-
-static void mlxsw_sx_port_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
-
- strlcpy(drvinfo->driver, mlxsw_sx_driver_name, sizeof(drvinfo->driver));
- strlcpy(drvinfo->version, mlxsw_sx_driver_version,
- sizeof(drvinfo->version));
- snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%d.%d.%d",
- mlxsw_sx->bus_info->fw_rev.major,
- mlxsw_sx->bus_info->fw_rev.minor,
- mlxsw_sx->bus_info->fw_rev.subminor);
- strlcpy(drvinfo->bus_info, mlxsw_sx->bus_info->device_name,
- sizeof(drvinfo->bus_info));
-}
-
-struct mlxsw_sx_port_hw_stats {
- char str[ETH_GSTRING_LEN];
- u64 (*getter)(const char *payload);
-};
-
-static const struct mlxsw_sx_port_hw_stats mlxsw_sx_port_hw_stats[] = {
- {
- .str = "a_frames_transmitted_ok",
- .getter = mlxsw_reg_ppcnt_a_frames_transmitted_ok_get,
- },
- {
- .str = "a_frames_received_ok",
- .getter = mlxsw_reg_ppcnt_a_frames_received_ok_get,
- },
- {
- .str = "a_frame_check_sequence_errors",
- .getter = mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get,
- },
- {
- .str = "a_alignment_errors",
- .getter = mlxsw_reg_ppcnt_a_alignment_errors_get,
- },
- {
- .str = "a_octets_transmitted_ok",
- .getter = mlxsw_reg_ppcnt_a_octets_transmitted_ok_get,
- },
- {
- .str = "a_octets_received_ok",
- .getter = mlxsw_reg_ppcnt_a_octets_received_ok_get,
- },
- {
- .str = "a_multicast_frames_xmitted_ok",
- .getter = mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get,
- },
- {
- .str = "a_broadcast_frames_xmitted_ok",
- .getter = mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get,
- },
- {
- .str = "a_multicast_frames_received_ok",
- .getter = mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get,
- },
- {
- .str = "a_broadcast_frames_received_ok",
- .getter = mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get,
- },
- {
- .str = "a_in_range_length_errors",
- .getter = mlxsw_reg_ppcnt_a_in_range_length_errors_get,
- },
- {
- .str = "a_out_of_range_length_field",
- .getter = mlxsw_reg_ppcnt_a_out_of_range_length_field_get,
- },
- {
- .str = "a_frame_too_long_errors",
- .getter = mlxsw_reg_ppcnt_a_frame_too_long_errors_get,
- },
- {
- .str = "a_symbol_error_during_carrier",
- .getter = mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get,
- },
- {
- .str = "a_mac_control_frames_transmitted",
- .getter = mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get,
- },
- {
- .str = "a_mac_control_frames_received",
- .getter = mlxsw_reg_ppcnt_a_mac_control_frames_received_get,
- },
- {
- .str = "a_unsupported_opcodes_received",
- .getter = mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get,
- },
- {
- .str = "a_pause_mac_ctrl_frames_received",
- .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_received_get,
- },
- {
- .str = "a_pause_mac_ctrl_frames_xmitted",
- .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_transmitted_get,
- },
-};
-
-#define MLXSW_SX_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sx_port_hw_stats)
-
-static void mlxsw_sx_port_get_strings(struct net_device *dev,
- u32 stringset, u8 *data)
-{
- u8 *p = data;
- int i;
-
- switch (stringset) {
- case ETH_SS_STATS:
- for (i = 0; i < MLXSW_SX_PORT_HW_STATS_LEN; i++) {
- memcpy(p, mlxsw_sx_port_hw_stats[i].str,
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- break;
- }
-}
-
-static void mlxsw_sx_port_get_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 *data)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
- int i;
- int err;
-
- mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sx_port->local_port,
- MLXSW_REG_PPCNT_IEEE_8023_CNT, 0);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ppcnt), ppcnt_pl);
- for (i = 0; i < MLXSW_SX_PORT_HW_STATS_LEN; i++)
- data[i] = !err ? mlxsw_sx_port_hw_stats[i].getter(ppcnt_pl) : 0;
-}
-
-static int mlxsw_sx_port_get_sset_count(struct net_device *dev, int sset)
-{
- switch (sset) {
- case ETH_SS_STATS:
- return MLXSW_SX_PORT_HW_STATS_LEN;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-struct mlxsw_sx_port_link_mode {
- u32 mask;
- u32 supported;
- u32 advertised;
- u32 speed;
-};
-
-static const struct mlxsw_sx_port_link_mode mlxsw_sx_port_link_mode[] = {
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_SGMII |
- MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX,
- .supported = SUPPORTED_1000baseKX_Full,
- .advertised = ADVERTISED_1000baseKX_Full,
- .speed = 1000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4,
- .supported = SUPPORTED_10000baseKX4_Full,
- .advertised = ADVERTISED_10000baseKX4_Full,
- .speed = 10000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR,
- .supported = SUPPORTED_10000baseKR_Full,
- .advertised = ADVERTISED_10000baseKR_Full,
- .speed = 10000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4,
- .supported = SUPPORTED_40000baseCR4_Full,
- .advertised = ADVERTISED_40000baseCR4_Full,
- .speed = 40000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4,
- .supported = SUPPORTED_40000baseKR4_Full,
- .advertised = ADVERTISED_40000baseKR4_Full,
- .speed = 40000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4,
- .supported = SUPPORTED_40000baseSR4_Full,
- .advertised = ADVERTISED_40000baseSR4_Full,
- .speed = 40000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4,
- .supported = SUPPORTED_40000baseLR4_Full,
- .advertised = ADVERTISED_40000baseLR4_Full,
- .speed = 40000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR |
- MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR |
- MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR,
- .speed = 25000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2 |
- MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2,
- .speed = 50000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,
- .speed = 100000,
- },
-};
-
-#define MLXSW_SX_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sx_port_link_mode)
-#define MLXSW_SX_PORT_BASE_SPEED 10000 /* Mb/s */
-
-static u32 mlxsw_sx_from_ptys_supported_port(u32 ptys_eth_proto)
-{
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_SGMII))
- return SUPPORTED_FIBRE;
-
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX))
- return SUPPORTED_Backplane;
- return 0;
-}
-
-static u32 mlxsw_sx_from_ptys_supported_link(u32 ptys_eth_proto)
-{
- u32 modes = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask)
- modes |= mlxsw_sx_port_link_mode[i].supported;
- }
- return modes;
-}
-
-static u32 mlxsw_sx_from_ptys_advert_link(u32 ptys_eth_proto)
-{
- u32 modes = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask)
- modes |= mlxsw_sx_port_link_mode[i].advertised;
- }
- return modes;
-}
-
-static void mlxsw_sx_from_ptys_speed_duplex(bool carrier_ok, u32 ptys_eth_proto,
- struct ethtool_link_ksettings *cmd)
-{
- u32 speed = SPEED_UNKNOWN;
- u8 duplex = DUPLEX_UNKNOWN;
- int i;
-
- if (!carrier_ok)
- goto out;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask) {
- speed = mlxsw_sx_port_link_mode[i].speed;
- duplex = DUPLEX_FULL;
- break;
- }
- }
-out:
- cmd->base.speed = speed;
- cmd->base.duplex = duplex;
-}
-
-static u8 mlxsw_sx_port_connector_port(u32 ptys_eth_proto)
-{
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_SGMII))
- return PORT_FIBRE;
-
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4))
- return PORT_DA;
-
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4))
- return PORT_NONE;
-
- return PORT_OTHER;
-}
-
-static int
-mlxsw_sx_port_get_link_ksettings(struct net_device *dev,
- struct ethtool_link_ksettings *cmd)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
- u32 eth_proto_cap;
- u32 eth_proto_admin;
- u32 eth_proto_oper;
- u32 supported, advertising, lp_advertising;
- int err;
-
- mlxsw_reg_ptys_eth_pack(ptys_pl, mlxsw_sx_port->local_port, 0, false);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
- if (err) {
- netdev_err(dev, "Failed to get proto");
- return err;
- }
- mlxsw_reg_ptys_eth_unpack(ptys_pl, &eth_proto_cap,
- &eth_proto_admin, &eth_proto_oper);
-
- supported = mlxsw_sx_from_ptys_supported_port(eth_proto_cap) |
- mlxsw_sx_from_ptys_supported_link(eth_proto_cap) |
- SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- advertising = mlxsw_sx_from_ptys_advert_link(eth_proto_admin);
- mlxsw_sx_from_ptys_speed_duplex(netif_carrier_ok(dev),
- eth_proto_oper, cmd);
-
- eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;
- cmd->base.port = mlxsw_sx_port_connector_port(eth_proto_oper);
- lp_advertising = mlxsw_sx_from_ptys_advert_link(eth_proto_oper);
-
- ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
- supported);
- ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
- advertising);
- ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
- lp_advertising);
-
- return 0;
-}
-
-static u32 mlxsw_sx_to_ptys_advert_link(u32 advertising)
-{
- u32 ptys_proto = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (advertising & mlxsw_sx_port_link_mode[i].advertised)
- ptys_proto |= mlxsw_sx_port_link_mode[i].mask;
- }
- return ptys_proto;
-}
-
-static u32 mlxsw_sx_to_ptys_speed(u32 speed)
-{
- u32 ptys_proto = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (speed == mlxsw_sx_port_link_mode[i].speed)
- ptys_proto |= mlxsw_sx_port_link_mode[i].mask;
- }
- return ptys_proto;
-}
-
-static u32 mlxsw_sx_to_ptys_upper_speed(u32 upper_speed)
-{
- u32 ptys_proto = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (mlxsw_sx_port_link_mode[i].speed <= upper_speed)
- ptys_proto |= mlxsw_sx_port_link_mode[i].mask;
- }
- return ptys_proto;
-}
-
-static int
-mlxsw_sx_port_set_link_ksettings(struct net_device *dev,
- const struct ethtool_link_ksettings *cmd)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
- u32 speed;
- u32 eth_proto_new;
- u32 eth_proto_cap;
- u32 eth_proto_admin;
- u32 advertising;
- bool is_up;
- int err;
-
- speed = cmd->base.speed;
-
- ethtool_convert_link_mode_to_legacy_u32(&advertising,
- cmd->link_modes.advertising);
-
- eth_proto_new = cmd->base.autoneg == AUTONEG_ENABLE ?
- mlxsw_sx_to_ptys_advert_link(advertising) :
- mlxsw_sx_to_ptys_speed(speed);
-
- mlxsw_reg_ptys_eth_pack(ptys_pl, mlxsw_sx_port->local_port, 0, false);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
- if (err) {
- netdev_err(dev, "Failed to get proto");
- return err;
- }
- mlxsw_reg_ptys_eth_unpack(ptys_pl, &eth_proto_cap, &eth_proto_admin,
- NULL);
-
- eth_proto_new = eth_proto_new & eth_proto_cap;
- if (!eth_proto_new) {
- netdev_err(dev, "Not supported proto admin requested");
- return -EINVAL;
- }
- if (eth_proto_new == eth_proto_admin)
- return 0;
-
- mlxsw_reg_ptys_eth_pack(ptys_pl, mlxsw_sx_port->local_port,
- eth_proto_new, true);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
- if (err) {
- netdev_err(dev, "Failed to set proto admin");
- return err;
- }
-
- err = mlxsw_sx_port_oper_status_get(mlxsw_sx_port, &is_up);
- if (err) {
- netdev_err(dev, "Failed to get oper status");
- return err;
- }
- if (!is_up)
- return 0;
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
- if (err) {
- netdev_err(dev, "Failed to set admin status");
- return err;
- }
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true);
- if (err) {
- netdev_err(dev, "Failed to set admin status");
- return err;
- }
-
- return 0;
-}
-
-static const struct ethtool_ops mlxsw_sx_port_ethtool_ops = {
- .get_drvinfo = mlxsw_sx_port_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_strings = mlxsw_sx_port_get_strings,
- .get_ethtool_stats = mlxsw_sx_port_get_stats,
- .get_sset_count = mlxsw_sx_port_get_sset_count,
- .get_link_ksettings = mlxsw_sx_port_get_link_ksettings,
- .set_link_ksettings = mlxsw_sx_port_set_link_ksettings,
-};
-
-static int mlxsw_sx_hw_id_get(struct mlxsw_sx *mlxsw_sx)
-{
- char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
- int err;
-
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(spad), spad_pl);
- if (err)
- return err;
- mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sx->hw_id);
- return 0;
-}
-
-static int mlxsw_sx_port_dev_addr_get(struct mlxsw_sx_port *mlxsw_sx_port)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- struct net_device *dev = mlxsw_sx_port->dev;
- char ppad_pl[MLXSW_REG_PPAD_LEN];
- int err;
-
- mlxsw_reg_ppad_pack(ppad_pl, false, 0);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ppad), ppad_pl);
- if (err)
- return err;
- mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, dev->dev_addr);
- /* The last byte value in base mac address is guaranteed
- * to be such it does not overflow when adding local_port
- * value.
- */
- dev->dev_addr[ETH_ALEN - 1] += mlxsw_sx_port->local_port;
- return 0;
-}
-
-static int mlxsw_sx_port_stp_state_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 vid, enum mlxsw_reg_spms_state state)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char *spms_pl;
- int err;
-
- spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);
- if (!spms_pl)
- return -ENOMEM;
- mlxsw_reg_spms_pack(spms_pl, mlxsw_sx_port->local_port);
- mlxsw_reg_spms_vid_pack(spms_pl, vid, state);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(spms), spms_pl);
- kfree(spms_pl);
- return err;
-}
-
-static int mlxsw_sx_port_ib_speed_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 speed, u16 width)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
-
- mlxsw_reg_ptys_ib_pack(ptys_pl, mlxsw_sx_port->local_port, speed,
- width);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
-}
-
-static int
-mlxsw_sx_port_speed_by_width_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 width)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- u32 upper_speed = MLXSW_SX_PORT_BASE_SPEED * width;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
- u32 eth_proto_admin;
-
- eth_proto_admin = mlxsw_sx_to_ptys_upper_speed(upper_speed);
- mlxsw_reg_ptys_eth_pack(ptys_pl, mlxsw_sx_port->local_port,
- eth_proto_admin, true);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
-}
-
-static int
-mlxsw_sx_port_mac_learning_mode_set(struct mlxsw_sx_port *mlxsw_sx_port,
- enum mlxsw_reg_spmlr_learn_mode mode)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char spmlr_pl[MLXSW_REG_SPMLR_LEN];
-
- mlxsw_reg_spmlr_pack(spmlr_pl, mlxsw_sx_port->local_port, mode);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(spmlr), spmlr_pl);
-}
-
-static int __mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
- u8 module, u8 width)
-{
- struct mlxsw_sx_port *mlxsw_sx_port;
- struct net_device *dev;
- int err;
-
- dev = alloc_etherdev(sizeof(struct mlxsw_sx_port));
- if (!dev)
- return -ENOMEM;
- SET_NETDEV_DEV(dev, mlxsw_sx->bus_info->dev);
- dev_net_set(dev, mlxsw_core_net(mlxsw_sx->core));
- mlxsw_sx_port = netdev_priv(dev);
- mlxsw_sx_port->dev = dev;
- mlxsw_sx_port->mlxsw_sx = mlxsw_sx;
- mlxsw_sx_port->local_port = local_port;
- mlxsw_sx_port->mapping.module = module;
-
- mlxsw_sx_port->pcpu_stats =
- netdev_alloc_pcpu_stats(struct mlxsw_sx_port_pcpu_stats);
- if (!mlxsw_sx_port->pcpu_stats) {
- err = -ENOMEM;
- goto err_alloc_stats;
- }
-
- dev->netdev_ops = &mlxsw_sx_port_netdev_ops;
- dev->ethtool_ops = &mlxsw_sx_port_ethtool_ops;
-
- err = mlxsw_sx_port_dev_addr_get(mlxsw_sx_port);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Unable to get port mac address\n",
- mlxsw_sx_port->local_port);
- goto err_dev_addr_get;
- }
-
- netif_carrier_off(dev);
-
- dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_LLTX | NETIF_F_SG |
- NETIF_F_VLAN_CHALLENGED;
-
- dev->min_mtu = 0;
- dev->max_mtu = ETH_MAX_MTU;
-
- /* Each packet needs to have a Tx header (metadata) on top all other
- * headers.
- */
- dev->needed_headroom = MLXSW_TXHDR_LEN;
-
- err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n",
- mlxsw_sx_port->local_port);
- goto err_port_system_port_mapping_set;
- }
-
- err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 0);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n",
- mlxsw_sx_port->local_port);
- goto err_port_swid_set;
- }
-
- err = mlxsw_sx_port_speed_by_width_set(mlxsw_sx_port, width);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set speed\n",
- mlxsw_sx_port->local_port);
- goto err_port_speed_set;
- }
-
- err = mlxsw_sx_port_mtu_eth_set(mlxsw_sx_port, ETH_DATA_LEN);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MTU\n",
- mlxsw_sx_port->local_port);
- goto err_port_mtu_set;
- }
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
- if (err)
- goto err_port_admin_status_set;
-
- err = mlxsw_sx_port_stp_state_set(mlxsw_sx_port,
- MLXSW_PORT_DEFAULT_VID,
- MLXSW_REG_SPMS_STATE_FORWARDING);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set STP state\n",
- mlxsw_sx_port->local_port);
- goto err_port_stp_state_set;
- }
-
- err = mlxsw_sx_port_mac_learning_mode_set(mlxsw_sx_port,
- MLXSW_REG_SPMLR_LEARN_MODE_DISABLE);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MAC learning mode\n",
- mlxsw_sx_port->local_port);
- goto err_port_mac_learning_mode_set;
- }
-
- err = register_netdev(dev);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to register netdev\n",
- mlxsw_sx_port->local_port);
- goto err_register_netdev;
- }
-
- mlxsw_core_port_eth_set(mlxsw_sx->core, mlxsw_sx_port->local_port,
- mlxsw_sx_port, dev);
- mlxsw_sx->ports[local_port] = mlxsw_sx_port;
- return 0;
-
-err_register_netdev:
-err_port_mac_learning_mode_set:
-err_port_stp_state_set:
-err_port_admin_status_set:
-err_port_mtu_set:
-err_port_speed_set:
- mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
-err_port_swid_set:
-err_port_system_port_mapping_set:
-err_dev_addr_get:
- free_percpu(mlxsw_sx_port->pcpu_stats);
-err_alloc_stats:
- free_netdev(dev);
- return err;
-}
-
-static int mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
- u8 module, u8 width)
-{
- int err;
-
- err = mlxsw_core_port_init(mlxsw_sx->core, local_port,
- module + 1, false, 0, false, 0,
- mlxsw_sx->hw_id, sizeof(mlxsw_sx->hw_id));
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to init core port\n",
- local_port);
- return err;
- }
- err = __mlxsw_sx_port_eth_create(mlxsw_sx, local_port, module, width);
- if (err)
- goto err_port_create;
-
- return 0;
-
-err_port_create:
- mlxsw_core_port_fini(mlxsw_sx->core, local_port);
- return err;
-}
-
-static void __mlxsw_sx_port_eth_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
-
- mlxsw_core_port_clear(mlxsw_sx->core, local_port, mlxsw_sx);
- unregister_netdev(mlxsw_sx_port->dev); /* This calls ndo_stop */
- mlxsw_sx->ports[local_port] = NULL;
- mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
- free_percpu(mlxsw_sx_port->pcpu_stats);
- free_netdev(mlxsw_sx_port->dev);
-}
-
-static bool mlxsw_sx_port_created(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- return mlxsw_sx->ports[local_port] != NULL;
-}
-
-static int __mlxsw_sx_port_ib_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
- u8 module, u8 width)
-{
- struct mlxsw_sx_port *mlxsw_sx_port;
- int err;
-
- mlxsw_sx_port = kzalloc(sizeof(*mlxsw_sx_port), GFP_KERNEL);
- if (!mlxsw_sx_port)
- return -ENOMEM;
- mlxsw_sx_port->mlxsw_sx = mlxsw_sx;
- mlxsw_sx_port->local_port = local_port;
- mlxsw_sx_port->mapping.module = module;
-
- err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n",
- mlxsw_sx_port->local_port);
- goto err_port_system_port_mapping_set;
- }
-
- /* Adding port to Infiniband swid (1) */
- err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 1);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n",
- mlxsw_sx_port->local_port);
- goto err_port_swid_set;
- }
-
- /* Expose the IB port number as it's front panel name */
- err = mlxsw_sx_port_ib_port_set(mlxsw_sx_port, module + 1);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set IB port\n",
- mlxsw_sx_port->local_port);
- goto err_port_ib_set;
- }
-
- /* Supports all speeds from SDR to FDR (bitmask) and support bus width
- * of 1x, 2x and 4x (3 bits bitmask)
- */
- err = mlxsw_sx_port_ib_speed_set(mlxsw_sx_port,
- MLXSW_REG_PTYS_IB_SPEED_EDR - 1,
- BIT(3) - 1);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set speed\n",
- mlxsw_sx_port->local_port);
- goto err_port_speed_set;
- }
-
- /* Change to the maximum MTU the device supports, the SMA will take
- * care of the active MTU
- */
- err = mlxsw_sx_port_mtu_ib_set(mlxsw_sx_port, MLXSW_IB_DEFAULT_MTU);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MTU\n",
- mlxsw_sx_port->local_port);
- goto err_port_mtu_set;
- }
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to change admin state to UP\n",
- mlxsw_sx_port->local_port);
- goto err_port_admin_set;
- }
-
- mlxsw_core_port_ib_set(mlxsw_sx->core, mlxsw_sx_port->local_port,
- mlxsw_sx_port);
- mlxsw_sx->ports[local_port] = mlxsw_sx_port;
- return 0;
-
-err_port_admin_set:
-err_port_mtu_set:
-err_port_speed_set:
-err_port_ib_set:
- mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
-err_port_swid_set:
-err_port_system_port_mapping_set:
- kfree(mlxsw_sx_port);
- return err;
-}
-
-static void __mlxsw_sx_port_ib_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
-
- mlxsw_core_port_clear(mlxsw_sx->core, local_port, mlxsw_sx);
- mlxsw_sx->ports[local_port] = NULL;
- mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
- mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
- kfree(mlxsw_sx_port);
-}
-
-static void __mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- enum devlink_port_type port_type =
- mlxsw_core_port_type_get(mlxsw_sx->core, local_port);
-
- if (port_type == DEVLINK_PORT_TYPE_ETH)
- __mlxsw_sx_port_eth_remove(mlxsw_sx, local_port);
- else if (port_type == DEVLINK_PORT_TYPE_IB)
- __mlxsw_sx_port_ib_remove(mlxsw_sx, local_port);
-}
-
-static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- __mlxsw_sx_port_remove(mlxsw_sx, local_port);
- mlxsw_core_port_fini(mlxsw_sx->core, local_port);
-}
-
-static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx)
-{
- int i;
-
- for (i = 1; i < mlxsw_core_max_ports(mlxsw_sx->core); i++)
- if (mlxsw_sx_port_created(mlxsw_sx, i))
- mlxsw_sx_port_remove(mlxsw_sx, i);
- kfree(mlxsw_sx->ports);
- mlxsw_sx->ports = NULL;
-}
-
-static int mlxsw_sx_ports_create(struct mlxsw_sx *mlxsw_sx)
-{
- unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sx->core);
- size_t alloc_size;
- u8 module, width;
- int i;
- int err;
-
- alloc_size = sizeof(struct mlxsw_sx_port *) * max_ports;
- mlxsw_sx->ports = kzalloc(alloc_size, GFP_KERNEL);
- if (!mlxsw_sx->ports)
- return -ENOMEM;
-
- for (i = 1; i < max_ports; i++) {
- err = mlxsw_sx_port_module_info_get(mlxsw_sx, i, &module,
- &width);
- if (err)
- goto err_port_module_info_get;
- if (!width)
- continue;
- err = mlxsw_sx_port_eth_create(mlxsw_sx, i, module, width);
- if (err)
- goto err_port_create;
- }
- return 0;
-
-err_port_create:
-err_port_module_info_get:
- for (i--; i >= 1; i--)
- if (mlxsw_sx_port_created(mlxsw_sx, i))
- mlxsw_sx_port_remove(mlxsw_sx, i);
- kfree(mlxsw_sx->ports);
- mlxsw_sx->ports = NULL;
- return err;
-}
-
-static void mlxsw_sx_pude_eth_event_func(struct mlxsw_sx_port *mlxsw_sx_port,
- enum mlxsw_reg_pude_oper_status status)
-{
- if (status == MLXSW_PORT_OPER_STATUS_UP) {
- netdev_info(mlxsw_sx_port->dev, "link up\n");
- netif_carrier_on(mlxsw_sx_port->dev);
- } else {
- netdev_info(mlxsw_sx_port->dev, "link down\n");
- netif_carrier_off(mlxsw_sx_port->dev);
- }
-}
-
-static void mlxsw_sx_pude_ib_event_func(struct mlxsw_sx_port *mlxsw_sx_port,
- enum mlxsw_reg_pude_oper_status status)
-{
- if (status == MLXSW_PORT_OPER_STATUS_UP)
- pr_info("ib link for port %d - up\n",
- mlxsw_sx_port->mapping.module + 1);
- else
- pr_info("ib link for port %d - down\n",
- mlxsw_sx_port->mapping.module + 1);
-}
-
-static void mlxsw_sx_pude_event_func(const struct mlxsw_reg_info *reg,
- char *pude_pl, void *priv)
-{
- struct mlxsw_sx *mlxsw_sx = priv;
- struct mlxsw_sx_port *mlxsw_sx_port;
- enum mlxsw_reg_pude_oper_status status;
- enum devlink_port_type port_type;
- u8 local_port;
-
- local_port = mlxsw_reg_pude_local_port_get(pude_pl);
- mlxsw_sx_port = mlxsw_sx->ports[local_port];
- if (!mlxsw_sx_port) {
- dev_warn(mlxsw_sx->bus_info->dev, "Port %d: Link event received for non-existent port\n",
- local_port);
- return;
- }
-
- status = mlxsw_reg_pude_oper_status_get(pude_pl);
- port_type = mlxsw_core_port_type_get(mlxsw_sx->core, local_port);
- if (port_type == DEVLINK_PORT_TYPE_ETH)
- mlxsw_sx_pude_eth_event_func(mlxsw_sx_port, status);
- else if (port_type == DEVLINK_PORT_TYPE_IB)
- mlxsw_sx_pude_ib_event_func(mlxsw_sx_port, status);
-}
-
-static void mlxsw_sx_rx_listener_func(struct sk_buff *skb, u8 local_port,
- void *priv)
-{
- struct mlxsw_sx *mlxsw_sx = priv;
- struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
- struct mlxsw_sx_port_pcpu_stats *pcpu_stats;
-
- if (unlikely(!mlxsw_sx_port)) {
- dev_warn_ratelimited(mlxsw_sx->bus_info->dev, "Port %d: skb received for non-existent port\n",
- local_port);
- return;
- }
-
- skb->dev = mlxsw_sx_port->dev;
-
- pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats);
- u64_stats_update_begin(&pcpu_stats->syncp);
- pcpu_stats->rx_packets++;
- pcpu_stats->rx_bytes += skb->len;
- u64_stats_update_end(&pcpu_stats->syncp);
-
- skb->protocol = eth_type_trans(skb, skb->dev);
- netif_receive_skb(skb);
-}
-
-static int mlxsw_sx_port_type_set(struct mlxsw_core *mlxsw_core, u8 local_port,
- enum devlink_port_type new_type)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core);
- u8 module, width;
- int err;
-
- if (!mlxsw_sx->ports || !mlxsw_sx->ports[local_port]) {
- dev_err(mlxsw_sx->bus_info->dev, "Port number \"%d\" does not exist\n",
- local_port);
- return -EINVAL;
- }
-
- if (new_type == DEVLINK_PORT_TYPE_AUTO)
- return -EOPNOTSUPP;
-
- __mlxsw_sx_port_remove(mlxsw_sx, local_port);
- err = mlxsw_sx_port_module_info_get(mlxsw_sx, local_port, &module,
- &width);
- if (err)
- goto err_port_module_info_get;
-
- if (new_type == DEVLINK_PORT_TYPE_ETH)
- err = __mlxsw_sx_port_eth_create(mlxsw_sx, local_port, module,
- width);
- else if (new_type == DEVLINK_PORT_TYPE_IB)
- err = __mlxsw_sx_port_ib_create(mlxsw_sx, local_port, module,
- width);
-
-err_port_module_info_get:
- return err;
-}
-
-enum {
- MLXSW_REG_HTGT_TRAP_GROUP_SX2_RX = 1,
- MLXSW_REG_HTGT_TRAP_GROUP_SX2_CTRL = 2,
-};
-
-#define MLXSW_SX_RXL(_trap_id) \
- MLXSW_RXL(mlxsw_sx_rx_listener_func, _trap_id, TRAP_TO_CPU, \
- false, SX2_RX, FORWARD)
-
-static const struct mlxsw_listener mlxsw_sx_listener[] = {
- MLXSW_EVENTL(mlxsw_sx_pude_event_func, PUDE, EMAD),
- MLXSW_SX_RXL(FDB_MC),
- MLXSW_SX_RXL(STP),
- MLXSW_SX_RXL(LACP),
- MLXSW_SX_RXL(EAPOL),
- MLXSW_SX_RXL(LLDP),
- MLXSW_SX_RXL(MMRP),
- MLXSW_SX_RXL(MVRP),
- MLXSW_SX_RXL(RPVST),
- MLXSW_SX_RXL(DHCP),
- MLXSW_SX_RXL(IGMP_QUERY),
- MLXSW_SX_RXL(IGMP_V1_REPORT),
- MLXSW_SX_RXL(IGMP_V2_REPORT),
- MLXSW_SX_RXL(IGMP_V2_LEAVE),
- MLXSW_SX_RXL(IGMP_V3_REPORT),
-};
-
-static int mlxsw_sx_traps_init(struct mlxsw_sx *mlxsw_sx)
-{
- char htgt_pl[MLXSW_REG_HTGT_LEN];
- int i;
- int err;
-
- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SX2_RX,
- MLXSW_REG_HTGT_INVALID_POLICER,
- MLXSW_REG_HTGT_DEFAULT_PRIORITY,
- MLXSW_REG_HTGT_DEFAULT_TC);
- mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
- MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_RX);
-
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(htgt), htgt_pl);
- if (err)
- return err;
-
- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SX2_CTRL,
- MLXSW_REG_HTGT_INVALID_POLICER,
- MLXSW_REG_HTGT_DEFAULT_PRIORITY,
- MLXSW_REG_HTGT_DEFAULT_TC);
- mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
- MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_CTRL);
-
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(htgt), htgt_pl);
- if (err)
- return err;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sx_listener); i++) {
- err = mlxsw_core_trap_register(mlxsw_sx->core,
- &mlxsw_sx_listener[i],
- mlxsw_sx);
- if (err)
- goto err_listener_register;
-
- }
- return 0;
-
-err_listener_register:
- for (i--; i >= 0; i--) {
- mlxsw_core_trap_unregister(mlxsw_sx->core,
- &mlxsw_sx_listener[i],
- mlxsw_sx);
- }
- return err;
-}
-
-static void mlxsw_sx_traps_fini(struct mlxsw_sx *mlxsw_sx)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sx_listener); i++) {
- mlxsw_core_trap_unregister(mlxsw_sx->core,
- &mlxsw_sx_listener[i],
- mlxsw_sx);
- }
-}
-
-static int mlxsw_sx_flood_init(struct mlxsw_sx *mlxsw_sx)
-{
- char sfgc_pl[MLXSW_REG_SFGC_LEN];
- char sgcr_pl[MLXSW_REG_SGCR_LEN];
- char *sftr_pl;
- int err;
-
- /* Configure a flooding table, which includes only CPU port. */
- sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
- if (!sftr_pl)
- return -ENOMEM;
- mlxsw_reg_sftr_pack(sftr_pl, 0, 0, MLXSW_REG_SFGC_TABLE_TYPE_SINGLE, 0,
- MLXSW_PORT_CPU_PORT, true);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sftr), sftr_pl);
- kfree(sftr_pl);
- if (err)
- return err;
-
- /* Flood different packet types using the flooding table. */
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_BROADCAST,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sgcr_pack(sgcr_pl, true);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sgcr), sgcr_pl);
-}
-
-static int mlxsw_sx_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
-{
- char htgt_pl[MLXSW_REG_HTGT_LEN];
-
- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD,
- MLXSW_REG_HTGT_INVALID_POLICER,
- MLXSW_REG_HTGT_DEFAULT_PRIORITY,
- MLXSW_REG_HTGT_DEFAULT_TC);
- mlxsw_reg_htgt_swid_set(htgt_pl, MLXSW_PORT_SWID_ALL_SWIDS);
- mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
- MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_EMAD);
- return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
-}
-
-static int mlxsw_sx_init(struct mlxsw_core *mlxsw_core,
- const struct mlxsw_bus_info *mlxsw_bus_info,
- struct netlink_ext_ack *extack)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core);
- int err;
-
- mlxsw_sx->core = mlxsw_core;
- mlxsw_sx->bus_info = mlxsw_bus_info;
-
- err = mlxsw_sx_hw_id_get(mlxsw_sx);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Failed to get switch HW ID\n");
- return err;
- }
-
- err = mlxsw_sx_ports_create(mlxsw_sx);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Failed to create ports\n");
- return err;
- }
-
- err = mlxsw_sx_traps_init(mlxsw_sx);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Failed to set traps\n");
- goto err_listener_register;
- }
-
- err = mlxsw_sx_flood_init(mlxsw_sx);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Failed to initialize flood tables\n");
- goto err_flood_init;
- }
-
- return 0;
-
-err_flood_init:
- mlxsw_sx_traps_fini(mlxsw_sx);
-err_listener_register:
- mlxsw_sx_ports_remove(mlxsw_sx);
- return err;
-}
-
-static void mlxsw_sx_fini(struct mlxsw_core *mlxsw_core)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core);
-
- mlxsw_sx_traps_fini(mlxsw_sx);
- mlxsw_sx_ports_remove(mlxsw_sx);
-}
-
-static const struct mlxsw_config_profile mlxsw_sx_config_profile = {
- .used_max_vepa_channels = 1,
- .max_vepa_channels = 0,
- .used_max_mid = 1,
- .max_mid = 7000,
- .used_max_pgt = 1,
- .max_pgt = 0,
- .used_max_system_port = 1,
- .max_system_port = 48000,
- .used_max_vlan_groups = 1,
- .max_vlan_groups = 127,
- .used_max_regions = 1,
- .max_regions = 400,
- .used_flood_tables = 1,
- .max_flood_tables = 2,
- .max_vid_flood_tables = 1,
- .used_flood_mode = 1,
- .flood_mode = 3,
- .used_max_ib_mc = 1,
- .max_ib_mc = 6,
- .used_max_pkey = 1,
- .max_pkey = 0,
- .swid_config = {
- {
- .used_type = 1,
- .type = MLXSW_PORT_SWID_TYPE_ETH,
- },
- {
- .used_type = 1,
- .type = MLXSW_PORT_SWID_TYPE_IB,
- }
- },
-};
-
-static struct mlxsw_driver mlxsw_sx_driver = {
- .kind = mlxsw_sx_driver_name,
- .priv_size = sizeof(struct mlxsw_sx),
- .init = mlxsw_sx_init,
- .fini = mlxsw_sx_fini,
- .basic_trap_groups_set = mlxsw_sx_basic_trap_groups_set,
- .txhdr_construct = mlxsw_sx_txhdr_construct,
- .txhdr_len = MLXSW_TXHDR_LEN,
- .profile = &mlxsw_sx_config_profile,
- .port_type_set = mlxsw_sx_port_type_set,
-};
-
-static const struct pci_device_id mlxsw_sx_pci_id_table[] = {
- {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHX2), 0},
- {0, },
-};
-
-static struct pci_driver mlxsw_sx_pci_driver = {
- .name = mlxsw_sx_driver_name,
- .id_table = mlxsw_sx_pci_id_table,
-};
-
-static int __init mlxsw_sx_module_init(void)
-{
- int err;
-
- err = mlxsw_core_driver_register(&mlxsw_sx_driver);
- if (err)
- return err;
-
- err = mlxsw_pci_driver_register(&mlxsw_sx_pci_driver);
- if (err)
- goto err_pci_driver_register;
-
- return 0;
-
-err_pci_driver_register:
- mlxsw_core_driver_unregister(&mlxsw_sx_driver);
- return err;
-}
-
-static void __exit mlxsw_sx_module_exit(void)
-{
- mlxsw_pci_driver_unregister(&mlxsw_sx_pci_driver);
- mlxsw_core_driver_unregister(&mlxsw_sx_driver);
-}
-
-module_init(mlxsw_sx_module_init);
-module_exit(mlxsw_sx_module_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Jiri Pirko <[email protected]>");
-MODULE_DESCRIPTION("Mellanox SwitchX-2 driver");
-MODULE_DEVICE_TABLE(pci, mlxsw_sx_pci_id_table);
diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c
index 9ed264ed7070..3532bfe936f6 100644
--- a/drivers/net/ethernet/micrel/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@ -2153,7 +2153,7 @@ static void sw_cfg_broad_storm(struct ksz_hw *hw, u8 percent)
}
/**
- * sw_get_board_storm - get broadcast storm threshold
+ * sw_get_broad_storm - get broadcast storm threshold
* @hw: The hardware instance.
* @percent: Buffer to store the broadcast storm threshold percentage.
*
@@ -2973,7 +2973,7 @@ static void hw_r_phy(struct ksz_hw *hw, int port, u16 reg, u16 *val)
}
/**
- * port_w_phy - write data to PHY register
+ * hw_w_phy - write data to PHY register
* @hw: The hardware instance.
* @port: Port to write.
* @reg: PHY register to write.
@@ -4782,7 +4782,7 @@ static void transmit_cleanup(struct dev_info *hw_priv, int normal)
}
/**
- * transmit_done - transmit done processing
+ * tx_done - transmit done processing
* @hw_priv: Network device.
*
* This routine is called when the transmit interrupt is triggered, indicating
diff --git a/drivers/net/ethernet/microchip/encx24j600.c b/drivers/net/ethernet/microchip/encx24j600.c
index 3658c4ae3c37..ee921a99e439 100644
--- a/drivers/net/ethernet/microchip/encx24j600.c
+++ b/drivers/net/ethernet/microchip/encx24j600.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/**
+/*
* Microchip ENCX24J600 ethernet driver
*
* Copyright (C) 2015 Gridpoint
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 04d067243457..46aee2c49f1b 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1387,8 +1387,7 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
gc = gd->gdma_context;
- rxq = kzalloc(sizeof(*rxq) +
- RX_BUFFERS_PER_QUEUE * sizeof(struct mana_recv_buf_oob),
+ rxq = kzalloc(struct_size(rxq, rx_oobs, RX_BUFFERS_PER_QUEUE),
GFP_KERNEL);
if (!rxq)
return NULL;
diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c
index b81e1487945c..51b4b25d15ad 100644
--- a/drivers/net/ethernet/natsemi/natsemi.c
+++ b/drivers/net/ethernet/natsemi/natsemi.c
@@ -969,7 +969,7 @@ static int natsemi_probe1(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
err_create_file:
- unregister_netdev(dev);
+ unregister_netdev(dev);
err_register_netdev:
iounmap(ioaddr);
@@ -3103,14 +3103,14 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCSMIIREG: /* Write MII PHY register. */
if (dev->if_port == PORT_TP) {
if ((data->phy_id & 0x1f) == np->phy_addr_external) {
- if ((data->reg_num & 0x1f) == MII_ADVERTISE)
+ if ((data->reg_num & 0x1f) == MII_ADVERTISE)
np->advertising = data->val_in;
mdio_write(dev, data->reg_num & 0x1f,
data->val_in);
}
} else {
if ((data->phy_id & 0x1f) == np->phy_addr_external) {
- if ((data->reg_num & 0x1f) == MII_ADVERTISE)
+ if ((data->reg_num & 0x1f) == MII_ADVERTISE)
np->advertising = data->val_in;
}
move_int_phy(dev, data->phy_id & 0x1f);
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 9cfcd5500462..27a65ab3d501 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -2743,7 +2743,7 @@ static int s2io_chk_rx_buffers(struct s2io_nic *nic, struct ring_info *ring)
}
/**
- * s2io_poll - Rx interrupt handler for NAPI support
+ * s2io_poll_msix - Rx interrupt handler for NAPI support
* @napi : pointer to the napi structure.
* @budget : The number of packets that were budgeted to be processed
* during one pass through the 'Poll" function.
@@ -5288,7 +5288,7 @@ s2io_ethtool_set_link_ksettings(struct net_device *dev,
}
/**
- * s2io_ethtol_get_link_ksettings - Return link specific information.
+ * s2io_ethtool_get_link_ksettings - Return link specific information.
* @dev: pointer to netdev
* @cmd : pointer to the structure with parameters given by ethtool
* to return link information.
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c
index 5162b938a1ac..38a273c4d593 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-config.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c
@@ -4884,7 +4884,7 @@ vpath_open_exit1:
}
/**
- * vxge_hw_vpath_rx_doorbell_post - Close the handle got from previous vpath
+ * vxge_hw_vpath_rx_doorbell_init - Close the handle got from previous vpath
* (vpath) open
* @vp: Handle got from previous vpath open
*
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index 87892bd992b1..b113c158d6e3 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -1799,7 +1799,7 @@ static void vxge_reset(struct work_struct *work)
}
/**
- * vxge_poll - Receive handler when Receive Polling is used.
+ * vxge_poll_msix - Receive handler when Receive Polling is used.
* @napi: pointer to the napi structure.
* @budget: Number of packets budgeted to be processed in this iteration.
*
@@ -4752,7 +4752,7 @@ _exit0:
}
/**
- * vxge_rem_nic - Free the PCI device
+ * vxge_remove - Free the PCI device
* @pdev: structure containing the PCI related information of the device.
* Description: This function is called by the Pci subsystem to release a
* PCI device and free up all resource held up by the device.
diff --git a/drivers/net/ethernet/netronome/nfp/ccm_mbox.c b/drivers/net/ethernet/netronome/nfp/ccm_mbox.c
index f0783aa9e66e..4247bca09807 100644
--- a/drivers/net/ethernet/netronome/nfp/ccm_mbox.c
+++ b/drivers/net/ethernet/netronome/nfp/ccm_mbox.c
@@ -36,7 +36,7 @@ enum nfp_net_mbox_cmsg_state {
};
/**
- * struct nfp_ccm_mbox_skb_cb - CCM mailbox specific info
+ * struct nfp_ccm_mbox_cmsg_cb - CCM mailbox specific info
* @state: processing state (/stage) of the message
* @err: error encountered during processing if any
* @max_len: max(request_len, reply_len)
diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
index d19c02e99114..ab70179728f6 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -21,7 +21,7 @@
#define NFP_TUN_PRE_TUN_IPV6_BIT BIT(7)
/**
- * struct nfp_tun_pre_run_rule - rule matched before decap
+ * struct nfp_tun_pre_tun_rule - rule matched before decap
* @flags: options for the rule offset
* @port_idx: index of destination MAC address for the rule
* @vlan_tci: VLAN info associated with MAC
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
index d4e02542e2e9..e2e5fd003ad6 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
@@ -24,7 +24,7 @@
#define NFFW_FWID_ALL 255
-/**
+/*
* NFFW_INFO_VERSION history:
* 0: This was never actually used (before versioning), but it refers to
* the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
index a6823c4d355d..108f312bc542 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
@@ -596,8 +596,6 @@ struct pch_gbe_adapter {
#define pch_gbe_hw_to_adapter(hw) container_of(hw, struct pch_gbe_adapter, hw)
-extern const char pch_driver_version[];
-
/* pch_gbe_main.c */
int pch_gbe_up(struct pch_gbe_adapter *adapter);
void pch_gbe_down(struct pch_gbe_adapter *adapter);
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
index a58f14aca10c..660b07cb5b92 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
@@ -8,6 +8,8 @@
#include "pch_gbe.h"
#include "pch_gbe_phy.h"
+static const char pch_driver_version[] = "1.01";
+
/*
* pch_gbe_stats - Stats item information
*/
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 334af49e5add..e351f3d1608f 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -8,15 +8,16 @@
#include "pch_gbe.h"
#include "pch_gbe_phy.h"
+
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_classify.h>
#include <linux/ptp_pch.h>
#include <linux/gpio.h>
-#define DRV_VERSION "1.01"
-const char pch_driver_version[] = DRV_VERSION;
-
#define PCH_GBE_MAR_ENTRIES 16
#define PCH_GBE_SHORT_PKT 64
#define DSC_INIT16 0xC000
@@ -97,8 +98,6 @@ const char pch_driver_version[] = DRV_VERSION;
#define PTP_L4_MULTICAST_SA "01:00:5e:00:01:81"
#define PTP_L2_MULTICAST_SA "01:1b:19:00:00:00"
-#define MINNOW_PHY_RESET_GPIO 13
-
static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
int data);
@@ -108,7 +107,7 @@ static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
{
u8 *data = skb->data;
unsigned int offset;
- u16 *hi, *id;
+ u16 hi, id;
u32 lo;
if (ptp_classify_raw(skb) == PTP_CLASS_NONE)
@@ -119,14 +118,11 @@ static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
return 0;
- hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
- id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
-
- memcpy(&lo, &hi[1], sizeof(lo));
+ hi = get_unaligned_be16(data + offset + OFF_PTP_SOURCE_UUID + 0);
+ lo = get_unaligned_be32(data + offset + OFF_PTP_SOURCE_UUID + 2);
+ id = get_unaligned_be16(data + offset + OFF_PTP_SEQUENCE_ID);
- return (uid_hi == *hi &&
- uid_lo == lo &&
- seqid == *id);
+ return (uid_hi == hi && uid_lo == lo && seqid == id);
}
static void
@@ -136,7 +132,6 @@ pch_rx_timestamp(struct pch_gbe_adapter *adapter, struct sk_buff *skb)
struct pci_dev *pdev;
u64 ns;
u32 hi, lo, val;
- u16 uid, seq;
if (!adapter->hwts_rx_en)
return;
@@ -152,10 +147,7 @@ pch_rx_timestamp(struct pch_gbe_adapter *adapter, struct sk_buff *skb)
lo = pch_src_uuid_lo_read(pdev);
hi = pch_src_uuid_hi_read(pdev);
- uid = hi & 0xffff;
- seq = (hi >> 16) & 0xffff;
-
- if (!pch_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
+ if (!pch_ptp_match(skb, hi, lo, hi >> 16))
goto out;
ns = pch_rx_snap_read(pdev);
@@ -298,15 +290,12 @@ static s32 pch_gbe_mac_read_mac_addr(struct pch_gbe_hw *hw)
* @reg: Pointer of register
* @bit: Busy bit
*/
-static void pch_gbe_wait_clr_bit(void *reg, u32 bit)
+static void pch_gbe_wait_clr_bit(void __iomem *reg, u32 bit)
{
u32 tmp;
/* wait busy */
- tmp = 1000;
- while ((ioread32(reg) & bit) && --tmp)
- cpu_relax();
- if (!tmp)
+ if (readx_poll_timeout_atomic(ioread32, reg, tmp, !(tmp & bit), 0, 10))
pr_err("Error: busy bit is not cleared\n");
}
@@ -490,18 +479,13 @@ u16 pch_gbe_mac_ctrl_miim(struct pch_gbe_hw *hw, u32 addr, u32 dir, u32 reg,
u16 data)
{
struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
- u32 data_out = 0;
- unsigned int i;
unsigned long flags;
+ u32 data_out;
spin_lock_irqsave(&hw->miim_lock, flags);
- for (i = 100; i; --i) {
- if ((ioread32(&hw->reg->MIIM) & PCH_GBE_MIIM_OPER_READY))
- break;
- udelay(20);
- }
- if (i == 0) {
+ if (readx_poll_timeout_atomic(ioread32, &hw->reg->MIIM, data_out,
+ data_out & PCH_GBE_MIIM_OPER_READY, 20, 2000)) {
netdev_err(adapter->netdev, "pch-gbe.miim won't go Ready\n");
spin_unlock_irqrestore(&hw->miim_lock, flags);
return 0; /* No way to indicate timeout error */
@@ -509,12 +493,8 @@ u16 pch_gbe_mac_ctrl_miim(struct pch_gbe_hw *hw, u32 addr, u32 dir, u32 reg,
iowrite32(((reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) |
(addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) |
dir | data), &hw->reg->MIIM);
- for (i = 0; i < 100; i++) {
- udelay(20);
- data_out = ioread32(&hw->reg->MIIM);
- if ((data_out & PCH_GBE_MIIM_OPER_READY))
- break;
- }
+ readx_poll_timeout_atomic(ioread32, &hw->reg->MIIM, data_out,
+ data_out & PCH_GBE_MIIM_OPER_READY, 20, 2000);
spin_unlock_irqrestore(&hw->miim_lock, flags);
netdev_dbg(adapter->netdev, "PHY %s: reg=%d, data=0x%04X\n",
@@ -2532,9 +2512,13 @@ static int pch_gbe_probe(struct pci_dev *pdev,
adapter->pdev = pdev;
adapter->hw.back = adapter;
adapter->hw.reg = pcim_iomap_table(pdev)[PCH_GBE_PCI_BAR];
+
adapter->pdata = (struct pch_gbe_privdata *)pci_id->driver_data;
- if (adapter->pdata && adapter->pdata->platform_init)
- adapter->pdata->platform_init(pdev);
+ if (adapter->pdata && adapter->pdata->platform_init) {
+ ret = adapter->pdata->platform_init(pdev);
+ if (ret)
+ goto err_free_netdev;
+ }
adapter->ptp_pdev =
pci_get_domain_bus_and_slot(pci_domain_nr(adapter->pdev->bus),
@@ -2624,26 +2608,45 @@ err_free_netdev:
return ret;
}
+static void pch_gbe_gpio_remove_table(void *table)
+{
+ gpiod_remove_lookup_table(table);
+}
+
+static int pch_gbe_gpio_add_table(struct device *dev, void *table)
+{
+ gpiod_add_lookup_table(table);
+ return devm_add_action_or_reset(dev, pch_gbe_gpio_remove_table, table);
+}
+
+static struct gpiod_lookup_table pch_gbe_minnow_gpio_table = {
+ .dev_id = "0000:02:00.1",
+ .table = {
+ GPIO_LOOKUP("sch_gpio.33158", 13, NULL, GPIO_ACTIVE_LOW),
+ {}
+ },
+};
+
/* The AR803X PHY on the MinnowBoard requires a physical pin to be toggled to
* ensure it is awake for probe and init. Request the line and reset the PHY.
*/
static int pch_gbe_minnow_platform_init(struct pci_dev *pdev)
{
- unsigned long flags = GPIOF_DIR_OUT | GPIOF_INIT_HIGH | GPIOF_EXPORT;
- unsigned gpio = MINNOW_PHY_RESET_GPIO;
+ struct gpio_desc *gpiod;
int ret;
- ret = devm_gpio_request_one(&pdev->dev, gpio, flags,
- "minnow_phy_reset");
- if (ret) {
- dev_err(&pdev->dev,
- "ERR: Can't request PHY reset GPIO line '%d'\n", gpio);
+ ret = pch_gbe_gpio_add_table(&pdev->dev, &pch_gbe_minnow_gpio_table);
+ if (ret)
return ret;
- }
- gpio_set_value(gpio, 0);
+ gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod))
+ return dev_err_probe(&pdev->dev, PTR_ERR(gpiod),
+ "Can't request PHY reset GPIO line\n");
+
+ gpiod_set_value(gpiod, 1);
usleep_range(1250, 1500);
- gpio_set_value(gpio, 1);
+ gpiod_set_value(gpiod, 0);
usleep_range(1250, 1500);
return ret;
@@ -2722,7 +2725,6 @@ module_pci_driver(pch_gbe_driver);
MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver");
MODULE_AUTHOR("LAPIS SEMICONDUCTOR, <[email protected]>");
MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id);
/* pch_gbe_main.c */
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
index 4eae4ee3538f..448567a1f520 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
@@ -453,7 +453,7 @@ static int qed_sp_iscsi_conn_update(struct qed_hwfn *p_hwfn,
struct iscsi_conn_update_ramrod_params *p_ramrod = NULL;
struct qed_spq_entry *p_ent = NULL;
struct qed_sp_init_data init_data;
- int rc = -EINVAL;
+ int rc;
u32 dval;
/* Get SPQ entry */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index d2c190732d3e..0a2f34fc8b24 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -746,7 +746,7 @@ static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)
}
/**
- * qlcnic_83xx_idc_cold_state
+ * qlcnic_83xx_idc_cold_state_handler
*
* @adapter: adapter structure
*
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
index c4297aea7d15..711609503ba6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
@@ -180,7 +180,7 @@ static int qlcnic_83xx_init_non_privileged_vnic(struct qlcnic_adapter *adapter)
}
/**
- * qlcnic_83xx_vnic_opmode
+ * qlcnic_83xx_config_vnic_opmode
*
* @adapter: adapter structure
* Identify virtual NIC operational modes.
diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c
index 702aa217a27a..d59fff2fbcc6 100644
--- a/drivers/net/ethernet/qualcomm/qca_debug.c
+++ b/drivers/net/ethernet/qualcomm/qca_debug.c
@@ -62,6 +62,7 @@ static const char qcaspi_gstrings_stats[][ETH_GSTRING_LEN] = {
"SPI errors",
"Write verify errors",
"Buffer available errors",
+ "Bad signature",
};
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index ab9b02574a15..79fe3ec4e581 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -504,8 +504,12 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event)
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
if (signature != QCASPI_GOOD_SIGNATURE) {
+ if (qca->sync == QCASPI_SYNC_READY)
+ qca->stats.bad_signature++;
+
qca->sync = QCASPI_SYNC_UNKNOWN;
netdev_dbg(qca->net_dev, "sync: got CPU on, but signature was invalid, restart\n");
+ return;
} else {
/* ensure that the WRBUF is empty */
qcaspi_read_register(qca, SPI_REG_WRBUF_SPC_AVA,
@@ -523,10 +527,14 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event)
switch (qca->sync) {
case QCASPI_SYNC_READY:
- /* Read signature, if not valid go to unknown state. */
+ /* Check signature twice, if not valid go to unknown state. */
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
+ if (signature != QCASPI_GOOD_SIGNATURE)
+ qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
+
if (signature != QCASPI_GOOD_SIGNATURE) {
qca->sync = QCASPI_SYNC_UNKNOWN;
+ qca->stats.bad_signature++;
netdev_dbg(qca->net_dev, "sync: bad signature, restart\n");
/* don't reset right away */
return;
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h
index d13a67e20d65..3067356106f0 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.h
+++ b/drivers/net/ethernet/qualcomm/qca_spi.h
@@ -75,6 +75,7 @@ struct qcaspi_stats {
u64 spi_err;
u64 write_verify_failed;
u64 buf_avail_err;
+ u64 bad_signature;
};
struct qcaspi {
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 4e44313b7651..9677e257e9a1 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -6,7 +6,7 @@
Copyright (C) 2000, 2001 David S. Miller ([email protected]) [sungem.c]
Copyright 2001 Manfred Spraul [natsemi.c]
Copyright 1999-2001 by Donald Becker. [natsemi.c]
- Written 1997-2001 by Donald Becker. [8139too.c]
+ Written 1997-2001 by Donald Becker. [8139too.c]
Copyright 1998-2001 by Jes Sorensen, <[email protected]>. [acenic.c]
This software may be used and distributed according to the terms of
@@ -947,8 +947,8 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev)
/* The chip only need report frame silently dropped. */
spin_lock_irqsave(&cp->lock, flags);
- if (netif_running(dev) && netif_device_present(dev))
- __cp_get_stats(cp);
+ if (netif_running(dev) && netif_device_present(dev))
+ __cp_get_stats(cp);
spin_unlock_irqrestore(&cp->lock, flags);
return &dev->stats;
diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c
index 1e5a453dea14..f0608f050050 100644
--- a/drivers/net/ethernet/realtek/8139too.c
+++ b/drivers/net/ethernet/realtek/8139too.c
@@ -11,7 +11,7 @@
-----<snip>-----
- Written 1997-2001 by Donald Becker.
+ Written 1997-2001 by Donald Becker.
This software may be used and distributed according to the
terms of the GNU General Public License (GPL), incorporated
herein by reference. Drivers based on or derived from this
@@ -548,8 +548,8 @@ static const struct {
{ "RTL-8100",
HW_REVID(1, 1, 1, 1, 0, 1, 0),
- HasLWake,
- },
+ HasLWake,
+ },
{ "RTL-8100B/8139D",
HW_REVID(1, 1, 1, 0, 1, 0, 1),
diff --git a/drivers/net/ethernet/realtek/atp.c b/drivers/net/ethernet/realtek/atp.c
index 9e3b35c97e63..b6c849b258a0 100644
--- a/drivers/net/ethernet/realtek/atp.c
+++ b/drivers/net/ethernet/realtek/atp.c
@@ -497,8 +497,8 @@ static void write_packet(long ioaddr, int length, unsigned char *packet, int pad
{
if (length & 1)
{
- length++;
- pad_len++;
+ length++;
+ pad_len++;
}
outb(EOC+MAR, ioaddr + PAR_DATA);
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 2c89cde7da1e..1663e0486496 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -34,8 +34,6 @@
#include "r8169.h"
#include "r8169_firmware.h"
-#define MODULENAME "r8169"
-
#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
@@ -1454,7 +1452,7 @@ static void rtl8169_get_drvinfo(struct net_device *dev,
struct rtl8169_private *tp = netdev_priv(dev);
struct rtl_fw *rtl_fw = tp->rtl_fw;
- strlcpy(info->driver, MODULENAME, sizeof(info->driver));
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
if (rtl_fw)
@@ -5305,7 +5303,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
- rc = pcim_iomap_regions(pdev, BIT(region), MODULENAME);
+ rc = pcim_iomap_regions(pdev, BIT(region), KBUILD_MODNAME);
if (rc < 0) {
dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
return rc;
@@ -5440,7 +5438,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
static struct pci_driver rtl8169_pci_driver = {
- .name = MODULENAME,
+ .name = KBUILD_MODNAME,
.id_table = rtl8169_pci_tbl,
.probe = rtl_init_one,
.remove = rtl_remove_one,
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
index 971f1e54b652..090bcd2fb758 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -789,7 +789,7 @@ static void sxgbe_tx_queue_clean(struct sxgbe_tx_queue *tqueue)
}
/**
- * sxgbe_tx_clean:
+ * sxgbe_tx_all_clean:
* @priv: driver private structure
* Description: it reclaims resources after transmission completes.
*/
@@ -1015,7 +1015,7 @@ static void sxgbe_tx_timer(struct timer_list *t)
}
/**
- * sxgbe_init_tx_coalesce: init tx mitigation options.
+ * sxgbe_tx_init_coalesce: init tx mitigation options.
* @priv: driver private structure
* Description:
* This inits the transmit coalesce parameters: i.e. timer rate,
diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c
index 65c98837ec45..16a4cbae9326 100644
--- a/drivers/net/ethernet/seeq/ether3.c
+++ b/drivers/net/ethernet/seeq/ether3.c
@@ -617,7 +617,7 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
break;
}
/*
- * ignore our own packets...
+ * ignore our own packets...
*/
if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) &&
!(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) {
@@ -672,7 +672,7 @@ done:
*/
if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
dev->stats.rx_dropped++;
- ether3_outw(next_ptr, REG_RECVPTR);
+ ether3_outw(next_ptr, REG_RECVPTR);
ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND);
}
@@ -690,11 +690,11 @@ static void ether3_tx(struct net_device *dev)
do {
unsigned long status;
- /*
+ /*
* Read the packet header
- */
+ */
ether3_setbuffer(dev, buffer_read, tx_tail * 0x600);
- status = ether3_readlong(dev);
+ status = ether3_readlong(dev);
/*
* Check to see if this packet has been transmitted
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index c746ca7235f1..4fd9903ffe98 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -722,8 +722,7 @@ static int efx_register_netdev(struct efx_nic *efx)
efx->state = STATE_READY;
smp_mb(); /* ensure we change state before checking reset_pending */
if (efx->reset_pending) {
- netif_err(efx, probe, efx->net_dev,
- "aborting probe due to scheduled reset\n");
+ pci_err(efx->pci_dev, "aborting probe due to scheduled reset\n");
rc = -EIO;
goto fail_locked;
}
@@ -990,8 +989,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
rc = efx->type->init(efx);
up_write(&efx->filter_sem);
if (rc) {
- netif_err(efx, probe, efx->net_dev,
- "failed to initialise NIC\n");
+ pci_err(efx->pci_dev, "failed to initialise NIC\n");
goto fail3;
}
@@ -1038,8 +1036,8 @@ static int efx_pci_probe_post_io(struct efx_nic *efx)
if (efx->type->sriov_init) {
rc = efx->type->sriov_init(efx);
if (rc)
- netif_err(efx, probe, efx->net_dev,
- "SR-IOV can't be enabled rc %d\n", rc);
+ pci_err(efx->pci_dev, "SR-IOV can't be enabled rc %d\n",
+ rc);
}
/* Determine netdevice features */
@@ -1106,8 +1104,7 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail1;
- netif_info(efx, probe, efx->net_dev,
- "Solarflare NIC detected\n");
+ pci_info(pci_dev, "Solarflare NIC detected\n");
if (!efx->type->is_vf)
efx_probe_vpd_strings(efx);
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 620c26f71be8..ca9c00b7f588 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -678,12 +678,12 @@ static int sis900_mii_probe(struct net_device *net_dev)
/* Reset phy if default phy is internal sis900 */
if ((sis_priv->mii->phy_id0 == 0x001D) &&
((sis_priv->mii->phy_id1&0xFFF0) == 0x8000))
- status = sis900_reset_phy(net_dev, sis_priv->cur_phy);
+ status = sis900_reset_phy(net_dev, sis_priv->cur_phy);
/* workaround for ICS1893 PHY */
if ((sis_priv->mii->phy_id0 == 0x0015) &&
((sis_priv->mii->phy_id1&0xFFF0) == 0xF440))
- mdio_write(net_dev, sis_priv->cur_phy, 0x0018, 0xD200);
+ mdio_write(net_dev, sis_priv->cur_phy, 0x0018, 0xD200);
if(status & MII_STAT_LINK){
while (poll_bit) {
@@ -727,7 +727,7 @@ static int sis900_mii_probe(struct net_device *net_dev)
static u16 sis900_default_phy(struct net_device * net_dev)
{
struct sis900_private *sis_priv = netdev_priv(net_dev);
- struct mii_phy *phy = NULL, *phy_home = NULL,
+ struct mii_phy *phy = NULL, *phy_home = NULL,
*default_phy = NULL, *phy_lan = NULL;
u16 status;
@@ -1339,18 +1339,18 @@ static void sis900_timer(struct timer_list *t)
} else {
/* Link ON -> OFF */
if (!(status & MII_STAT_LINK)){
- netif_carrier_off(net_dev);
+ netif_carrier_off(net_dev);
if(netif_msg_link(sis_priv))
- printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+ printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
- /* Change mode issue */
- if ((mii_phy->phy_id0 == 0x001D) &&
- ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
- sis900_reset_phy(net_dev, sis_priv->cur_phy);
+ /* Change mode issue */
+ if ((mii_phy->phy_id0 == 0x001D) &&
+ ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
+ sis900_reset_phy(net_dev, sis_priv->cur_phy);
sis630_set_eq(net_dev, sis_priv->chipset_rev);
- goto LookForLink;
+ goto LookForLink;
}
}
@@ -2331,7 +2331,7 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
case IF_PORT_10BASE2: /* 10Base2 */
case IF_PORT_AUI: /* AUI */
case IF_PORT_100BASEFX: /* 100BaseFx */
- /* These Modes are not supported (are they?)*/
+ /* These Modes are not supported (are they?)*/
return -EOPNOTSUPP;
default:
diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c
index 4b2330deed47..bf7c8c8b1350 100644
--- a/drivers/net/ethernet/smsc/smc9194.c
+++ b/drivers/net/ethernet/smsc/smc9194.c
@@ -182,8 +182,8 @@ struct smc_local {
struct sk_buff * saved_skb;
/*
- . This keeps track of how many packets that I have
- . sent out. When an TX_EMPTY interrupt comes, I know
+ . This keeps track of how many packets that I have
+ . sent out. When an TX_EMPTY interrupt comes, I know
. that all of these have been sent.
*/
int packets_waiting;
@@ -343,7 +343,7 @@ static void smc_reset( int ioaddr )
/* Note: It doesn't seem that waiting for the MMU busy is needed here,
but this is a place where future chipsets _COULD_ break. Be wary
- of issuing another MMU command right after this */
+ of issuing another MMU command right after this */
outb( 0, ioaddr + INT_MASK );
}
@@ -521,9 +521,9 @@ static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
SMC_SELECT_BANK( 2 );
outw( MC_ALLOC | numPages, ioaddr + MMU_CMD );
/*
- . Performance Hack
+ . Performance Hack
.
- . wait a short amount of time.. if I can send a packet now, I send
+ . wait a short amount of time.. if I can send a packet now, I send
. it now. Otherwise, I enable an interrupt and wait for one to be
. available.
.
@@ -540,17 +540,17 @@ static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
if ( status & IM_ALLOC_INT ) {
/* acknowledge the interrupt */
outb( IM_ALLOC_INT, ioaddr + INTERRUPT );
- break;
+ break;
}
- } while ( -- time_out );
+ } while ( -- time_out );
- if ( !time_out ) {
+ if ( !time_out ) {
/* oh well, wait until the chip finds memory later */
SMC_ENABLE_INT( IM_ALLOC_INT );
PRINTK2((CARDNAME": memory allocation deferred.\n"));
/* it's deferred, but I'll handle it later */
return NETDEV_TX_OK;
- }
+ }
/* or YES! I can send the packet now.. */
smc_hardware_send_packet(dev);
netif_wake_queue(dev);
@@ -616,7 +616,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
#endif
/* send the packet length ( +6 for status, length and ctl byte )
- and the status word ( set to zeros ) */
+ and the status word ( set to zeros ) */
#ifdef USE_32_BIT
outl( (length +6 ) << 16 , ioaddr + DATA_1 );
#else
@@ -629,8 +629,8 @@ static void smc_hardware_send_packet( struct net_device * dev )
/* send the actual data
. I _think_ it's faster to send the longs first, and then
. mop up by sending the last word. It depends heavily
- . on alignment, at least on the 486. Maybe it would be
- . a good idea to check which is optimal? But that could take
+ . on alignment, at least on the 486. Maybe it would be
+ . a good idea to check which is optimal? But that could take
. almost as much time as is saved?
*/
#ifdef USE_32_BIT
@@ -757,7 +757,7 @@ static int __init smc_findirq(int ioaddr)
outb( IM_ALLOC_INT, ioaddr + INT_MASK );
/*
- . Allocate 512 bytes of memory. Note that the chip was just
+ . Allocate 512 bytes of memory. Note that the chip was just
. reset so all the memory is available
*/
outw( MC_ALLOC | 1, ioaddr + MMU_CMD );
@@ -871,7 +871,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
goto err_out;
}
/* The above MIGHT indicate a device, but I need to write to further
- test this. */
+ test this. */
outw( 0x0, ioaddr + BANK_SELECT );
bank = inw( ioaddr + BANK_SELECT );
if ( (bank & 0xFF00 ) != 0x3300 ) {
@@ -879,7 +879,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
goto err_out;
}
/* well, we've already written once, so hopefully another time won't
- hurt. This time, I need to switch the bank register to bank 1,
+ hurt. This time, I need to switch the bank register to bank 1,
so I can access the base address register */
SMC_SELECT_BANK(1);
base_address_register = inw( ioaddr + BASE );
@@ -917,7 +917,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
/*
- . Get the MAC address ( bank 1, regs 4 - 9 )
+ . Get the MAC address ( bank 1, regs 4 - 9 )
*/
SMC_SELECT_BANK( 1 );
for ( i = 0; i < 6; i += 2 ) {
@@ -938,8 +938,8 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
/*
Now, I want to find out more about the chip. This is sort of
- redundant, but it's cleaner to have it in both, rather than having
- one VERY long probe procedure.
+ redundant, but it's cleaner to have it in both, rather than having
+ one VERY long probe procedure.
*/
SMC_SELECT_BANK(3);
revision_register = inw( ioaddr + REVISION );
@@ -967,7 +967,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
/*
. If dev->irq is 0, then the device has to be banged on to see
. what the IRQ is.
- .
+ .
. This banging doesn't always detect the IRQ, for unknown reasons.
. a workaround is to reset the chip and try again.
.
@@ -978,7 +978,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
.
. Specifying an IRQ is done with the assumption that the user knows
. what (s)he is doing. No checking is done!!!!
- .
+ .
*/
if ( dev->irq < 2 ) {
int trials;
@@ -1070,7 +1070,7 @@ static int smc_open(struct net_device *dev)
}
/*
- According to Becker, I have to set the hardware address
+ According to Becker, I have to set the hardware address
at this point, because the (l)user can set it with an
ioctl. Easily done...
*/
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index cbde83f620a0..813ea941b91a 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -671,19 +671,19 @@ smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
status = SMC_GET_INT(lp);
if (status & IM_ALLOC_INT) {
SMC_ACK_INT(lp, IM_ALLOC_INT);
- break;
+ break;
}
- } while (--poll_count);
+ } while (--poll_count);
smc_special_unlock(&lp->lock, flags);
lp->pending_tx_skb = skb;
- if (!poll_count) {
+ if (!poll_count) {
/* oh well, wait until the chip finds memory later */
netif_stop_queue(dev);
DBG(2, dev, "TX memory allocation deferred.\n");
SMC_ENABLE_INT(lp, IM_ALLOC_INT);
- } else {
+ } else {
/*
* Allocation succeeded: push packet to the chip's own memory
* immediately.
@@ -1790,7 +1790,7 @@ static int smc_findirq(struct smc_local *lp)
SMC_SET_INT_MASK(lp, IM_ALLOC_INT);
/*
- * Allocate 512 bytes of memory. Note that the chip was just
+ * Allocate 512 bytes of memory. Note that the chip was just
* reset so all the memory is available
*/
SMC_SET_MMU_CMD(lp, MC_ALLOC | 1);
@@ -1998,8 +1998,8 @@ static int smc_probe(struct net_device *dev, void __iomem *ioaddr,
/* Grab the IRQ */
retval = request_irq(dev->irq, smc_interrupt, irq_flags, dev->name, dev);
- if (retval)
- goto err_out;
+ if (retval)
+ goto err_out;
#ifdef CONFIG_ARCH_PXA
# ifdef SMC_USE_PXA_DMA
diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c
index fcbb4bb31408..5eb6bb4f7b6c 100644
--- a/drivers/net/ethernet/socionext/sni_ave.c
+++ b/drivers/net/ethernet/socionext/sni_ave.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* sni_ave.c - Socionext UniPhier AVE ethernet driver
* Copyright 2014 Panasonic Corporation
* Copyright 2015-2017 Socionext Inc.
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index 80728a4c0e3f..e36a8cc59ad0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -429,6 +429,17 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->force_sf_dma_mode = 0;
plat->tso_en = 1;
+ /* Multiplying factor to the clk_eee_i clock time
+ * period to make it closer to 100 ns. This value
+ * should be programmed such that the clk_eee_time_period *
+ * (MULT_FACT_100NS + 1) should be within 80 ns to 120 ns
+ * clk_eee frequency is 19.2Mhz
+ * clk_eee_time_period is 52ns
+ * 52ns * (1 + 1) = 104ns
+ * MULT_FACT_100NS = 1
+ */
+ plat->mult_fact_100ns = 1;
+
plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
for (i = 0; i < plat->rx_queues_to_use; i++) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 8d28a536e1bb..280ac0129572 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -33,11 +33,13 @@ struct rk_gmac_ops {
void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
+ u32 regs[];
};
struct rk_priv_data {
struct platform_device *pdev;
phy_interface_t phy_iface;
+ int id;
struct regulator *regulator;
bool suspended;
const struct rk_gmac_ops *ops;
@@ -482,6 +484,54 @@ static const struct rk_gmac_ops rk3288_ops = {
.set_rmii_speed = rk3288_set_rmii_speed,
};
+#define RK3308_GRF_MAC_CON0 0x04a0
+
+/* RK3308_GRF_MAC_CON0 */
+#define RK3308_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(2) | GRF_CLR_BIT(3) | \
+ GRF_BIT(4))
+#define RK3308_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3308_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3308_GMAC_SPEED_10M GRF_CLR_BIT(0)
+#define RK3308_GMAC_SPEED_100M GRF_BIT(0)
+
+static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void rk3308_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rk3308_ops = {
+ .set_to_rmii = rk3308_set_to_rmii,
+ .set_rmii_speed = rk3308_set_rmii_speed,
+};
+
#define RK3328_GRF_MAC_CON0 0x0900
#define RK3328_GRF_MAC_CON1 0x0904
#define RK3328_GRF_MAC_CON2 0x0908
@@ -948,6 +998,107 @@ static const struct rk_gmac_ops rk3399_ops = {
.set_rmii_speed = rk3399_set_rmii_speed,
};
+#define RK3568_GRF_GMAC0_CON0 0x0380
+#define RK3568_GRF_GMAC0_CON1 0x0384
+#define RK3568_GRF_GMAC1_CON0 0x0388
+#define RK3568_GRF_GMAC1_CON1 0x038c
+
+/* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */
+#define RK3568_GMAC_PHY_INTF_SEL_RGMII \
+ (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
+#define RK3568_GMAC_PHY_INTF_SEL_RMII \
+ (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
+#define RK3568_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3568_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
+#define RK3568_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1)
+#define RK3568_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
+#define RK3568_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
+
+/* RK3568_GRF_GMAC0_CON0 && RK3568_GRF_GMAC1_CON0 */
+#define RK3568_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3568_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ u32 con0, con1;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ con0 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON0 :
+ RK3568_GRF_GMAC0_CON0;
+ con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+
+ regmap_write(bsp_priv->grf, con0,
+ RK3568_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));
+
+ regmap_write(bsp_priv->grf, con1,
+ RK3568_GMAC_PHY_INTF_SEL_RGMII |
+ RK3568_GMAC_RXCLK_DLY_ENABLE |
+ RK3568_GMAC_TXCLK_DLY_ENABLE);
+}
+
+static void rk3568_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ u32 con1;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+ regmap_write(bsp_priv->grf, con1, RK3568_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void rk3568_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ unsigned long rate;
+ int ret;
+
+ switch (speed) {
+ case 10:
+ rate = 2500000;
+ break;
+ case 100:
+ rate = 25000000;
+ break;
+ case 1000:
+ rate = 125000000;
+ break;
+ default:
+ dev_err(dev, "unknown speed value for GMAC speed=%d", speed);
+ return;
+ }
+
+ ret = clk_set_rate(bsp_priv->clk_mac_speed, rate);
+ if (ret)
+ dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n",
+ __func__, rate, ret);
+}
+
+static const struct rk_gmac_ops rk3568_ops = {
+ .set_to_rgmii = rk3568_set_to_rgmii,
+ .set_to_rmii = rk3568_set_to_rmii,
+ .set_rgmii_speed = rk3568_set_gmac_speed,
+ .set_rmii_speed = rk3568_set_gmac_speed,
+ .regs = {
+ 0xfe2a0000, /* gmac0 */
+ 0xfe010000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+};
+
#define RV1108_GRF_GMAC_CON0 0X0900
/* RV1108_GRF_GMAC_CON0 */
@@ -1216,6 +1367,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
{
struct rk_priv_data *bsp_priv;
struct device *dev = &pdev->dev;
+ struct resource *res;
int ret;
const char *strings = NULL;
int value;
@@ -1227,6 +1379,22 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
of_get_phy_mode(dev->of_node, &bsp_priv->phy_iface);
bsp_priv->ops = ops;
+ /* Some SoCs have multiple MAC controllers, which need
+ * to be distinguished.
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ int i = 0;
+
+ while (ops->regs[i]) {
+ if (ops->regs[i] == res->start) {
+ bsp_priv->id = i;
+ break;
+ }
+ i++;
+ }
+ }
+
bsp_priv->regulator = devm_regulator_get_optional(dev, "phy");
if (IS_ERR(bsp_priv->regulator)) {
if (PTR_ERR(bsp_priv->regulator) == -EPROBE_DEFER) {
@@ -1294,11 +1462,36 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
return bsp_priv;
}
+static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)
+{
+ switch (bsp_priv->phy_iface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (!bsp_priv->ops->set_to_rgmii)
+ return -EINVAL;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if (!bsp_priv->ops->set_to_rmii)
+ return -EINVAL;
+ break;
+ default:
+ dev_err(&bsp_priv->pdev->dev,
+ "unsupported interface %d", bsp_priv->phy_iface);
+ }
+ return 0;
+}
+
static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
{
int ret;
struct device *dev = &bsp_priv->pdev->dev;
+ ret = rk_gmac_check_ops(bsp_priv);
+ if (ret)
+ return ret;
+
ret = gmac_clk_enable(bsp_priv, true);
if (ret)
return ret;
@@ -1369,10 +1562,12 @@ static void rk_fix_speed(void *priv, unsigned int speed)
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
- bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
+ if (bsp_priv->ops->set_rgmii_speed)
+ bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
break;
case PHY_INTERFACE_MODE_RMII:
- bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
+ if (bsp_priv->ops->set_rmii_speed)
+ bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
break;
default:
dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
@@ -1400,7 +1595,11 @@ static int rk_gmac_probe(struct platform_device *pdev)
if (IS_ERR(plat_dat))
return PTR_ERR(plat_dat);
- plat_dat->has_gmac = true;
+ /* If the stmmac is not already selected as gmac4,
+ * then make sure we fallback to gmac.
+ */
+ if (!plat_dat->has_gmac4)
+ plat_dat->has_gmac = true;
plat_dat->fix_mac_speed = rk_fix_speed;
plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data);
@@ -1477,10 +1676,12 @@ static const struct of_device_id rk_gmac_dwmac_match[] = {
{ .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops },
{ .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
{ .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
+ { .compatible = "rockchip,rk3308-gmac", .data = &rk3308_ops },
{ .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },
{ .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },
{ .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
{ .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },
+ { .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops },
{ .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },
{ }
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 6d5e0f2b03ce..75a8b90c202a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -623,6 +623,8 @@ struct stmmac_mmc_ops {
stmmac_do_callback(__priv, xpcs, link_up, __args)
#define stmmac_xpcs_probe(__priv, __args...) \
stmmac_do_callback(__priv, xpcs, probe, __args)
+#define stmmac_xpcs_config_eee(__priv, __args...) \
+ stmmac_do_callback(__priv, xpcs, config_eee, __args)
struct stmmac_regs_off {
u32 ptp_off;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 61b11639ee0c..1f6d749fd9a3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -720,6 +720,12 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
netdev_warn(priv->dev,
"Setting EEE tx-lpi is not supported\n");
+ ret = stmmac_xpcs_config_eee(priv, &priv->hw->xpcs_args,
+ priv->plat->mult_fact_100ns,
+ edata->eee_enabled);
+ if (ret)
+ return ret;
+
if (!edata->eee_enabled)
stmmac_disable_eee_mode(priv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 345b4c6d1fd4..bf9fe25fed69 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -5167,12 +5167,9 @@ read_again:
dma_sync_single_for_cpu(priv->device, buf->addr,
buf1_len, dma_dir);
- xdp.data = page_address(buf->page) + buf->page_offset;
- xdp.data_end = xdp.data + buf1_len;
- xdp.data_hard_start = page_address(buf->page);
- xdp_set_data_meta_invalid(&xdp);
- xdp.frame_sz = buf_sz;
- xdp.rxq = &rx_q->xdp_rxq;
+ xdp_init_buff(&xdp, buf_sz, &rx_q->xdp_rxq);
+ xdp_prepare_buff(&xdp, page_address(buf->page),
+ buf->page_offset, buf1_len, false);
pre_len = xdp.data_end - xdp.data_hard_start -
buf->page_offset;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 1e17a23d9118..97a1fedcc9ac 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -230,8 +230,6 @@ static int stmmac_mtl_setup(struct platform_device *pdev,
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WFQ;
else if (of_property_read_bool(tx_node, "snps,tx-sched-dwrr"))
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_DWRR;
- else if (of_property_read_bool(tx_node, "snps,tx-sched-sp"))
- plat->tx_sched_algorithm = MTL_TX_ALGORITHM_SP;
else
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_SP;
diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c
index 54f45d8c79a7..981685c88308 100644
--- a/drivers/net/ethernet/sun/cassini.c
+++ b/drivers/net/ethernet/sun/cassini.c
@@ -486,7 +486,7 @@ page_err:
/* initialize spare pool of rx buffers, but allocate during the open */
static void cas_spare_init(struct cas *cp)
{
- spin_lock(&cp->rx_inuse_lock);
+ spin_lock(&cp->rx_inuse_lock);
INIT_LIST_HEAD(&cp->rx_inuse_list);
spin_unlock(&cp->rx_inuse_lock);
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index 9790656cf970..cfb9e21b18b7 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -1258,8 +1258,8 @@ static void gem_begin_auto_negotiation(struct gem *gp,
&advertising, ep->link_modes.advertising);
if (gp->phy_type != phy_mii_mdio0 &&
- gp->phy_type != phy_mii_mdio1)
- goto non_mii;
+ gp->phy_type != phy_mii_mdio1)
+ goto non_mii;
/* Setup advertise */
if (found_mii_phy(gp))
@@ -1410,7 +1410,7 @@ static int gem_set_link_modes(struct gem *gp)
if (gp->phy_type == phy_serialink ||
gp->phy_type == phy_serdes) {
- u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
+ u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
if (pcs_lpa & (PCS_MIIADV_SP | PCS_MIIADV_AP))
pause = 1;
@@ -1892,7 +1892,7 @@ static void gem_init_mac(struct gem *gp)
static void gem_init_pause_thresholds(struct gem *gp)
{
- u32 cfg;
+ u32 cfg;
/* Calculate pause thresholds. Setting the OFF threshold to the
* full RX fifo size effectively disables PAUSE generation which
@@ -1914,15 +1914,15 @@ static void gem_init_pause_thresholds(struct gem *gp)
/* Configure the chip "burst" DMA mode & enable some
* HW bug fixes on Apple version
*/
- cfg = 0;
- if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ cfg = 0;
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
cfg |= GREG_CFG_RONPAULBIT | GREG_CFG_ENBUG2FIX;
#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA)
- cfg |= GREG_CFG_IBURST;
+ cfg |= GREG_CFG_IBURST;
#endif
- cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
- cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
- writel(cfg, gp->regs + GREG_CFG);
+ cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
+ cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
+ writel(cfg, gp->regs + GREG_CFG);
/* If Infinite Burst didn't stick, then use different
* thresholds (and Apple bug fixes don't exist)
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index 54b53dbdb33c..a2c1a404c52d 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -2286,8 +2286,8 @@ static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct happy_meal *hp = netdev_priv(dev);
- int entry;
- u32 tx_flags;
+ int entry;
+ u32 tx_flags;
tx_flags = TXFLAG_OWN;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -2301,7 +2301,7 @@ static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb,
spin_lock_irq(&hp->happy_lock);
- if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+ if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irq(&hp->happy_lock);
printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index d828f856237a..0c75e0576ee1 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -70,7 +70,7 @@ enum {
};
/**
- * struct ale_dev_id - The ALE version/SoC specific configuration
+ * struct cpsw_ale_dev_id - The ALE version/SoC specific configuration
* @dev_id: ALE version/SoC id
* @features: features supported by ALE
* @tbl_entries: number of ALE entries
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index fecc4d7b00b0..88426b5e410b 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -1897,7 +1897,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
}
/**
- * tx_srv - transmit interrupt service
+ * velocity_tx_srv - transmit interrupt service
* @vptr: Velocity
*
* Scan the queues looking for transmitted packets that
@@ -2453,7 +2453,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
/**
- * velocity_get_status - statistics callback
+ * velocity_get_stats - statistics callback
* @dev: network device
*
* Callback from the network layer to allow driver statistics
@@ -3723,7 +3723,7 @@ static int __init velocity_init_module(void)
}
/**
- * velocity_cleanup - module unload
+ * velocity_cleanup_module - module unload
*
* When the velocity hardware is unloaded this function is called.
* It will clean up the notifiers and the unregister the PCI
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
index 2049d76a0e68..4f6db6f5c272 100644
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -1232,7 +1232,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (pktlen < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
+ return NETDEV_TX_OK;
pktlen = ETH_ZLEN;
}
diff --git a/drivers/net/mdio/mdio-ipq8064.c b/drivers/net/mdio/mdio-ipq8064.c
index 8fe8f0119fc1..bd1aea2d5a26 100644
--- a/drivers/net/mdio/mdio-ipq8064.c
+++ b/drivers/net/mdio/mdio-ipq8064.c
@@ -7,33 +7,33 @@
#include <linux/delay.h>
#include <linux/kernel.h>
-#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_mdio.h>
-#include <linux/phy.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* MII address register definitions */
-#define MII_ADDR_REG_ADDR 0x10
-#define MII_BUSY BIT(0)
-#define MII_WRITE BIT(1)
-#define MII_CLKRANGE_60_100M (0 << 2)
-#define MII_CLKRANGE_100_150M (1 << 2)
-#define MII_CLKRANGE_20_35M (2 << 2)
-#define MII_CLKRANGE_35_60M (3 << 2)
-#define MII_CLKRANGE_150_250M (4 << 2)
-#define MII_CLKRANGE_250_300M (5 << 2)
+#define MII_ADDR_REG_ADDR 0x10
+#define MII_BUSY BIT(0)
+#define MII_WRITE BIT(1)
+#define MII_CLKRANGE(x) ((x) << 2)
+#define MII_CLKRANGE_60_100M MII_CLKRANGE(0)
+#define MII_CLKRANGE_100_150M MII_CLKRANGE(1)
+#define MII_CLKRANGE_20_35M MII_CLKRANGE(2)
+#define MII_CLKRANGE_35_60M MII_CLKRANGE(3)
+#define MII_CLKRANGE_150_250M MII_CLKRANGE(4)
+#define MII_CLKRANGE_250_300M MII_CLKRANGE(5)
#define MII_CLKRANGE_MASK GENMASK(4, 2)
#define MII_REG_SHIFT 6
#define MII_REG_MASK GENMASK(10, 6)
#define MII_ADDR_SHIFT 11
#define MII_ADDR_MASK GENMASK(15, 11)
-#define MII_DATA_REG_ADDR 0x14
+#define MII_DATA_REG_ADDR 0x14
-#define MII_MDIO_DELAY_USEC (1000)
-#define MII_MDIO_RETRY_MSEC (10)
+#define MII_MDIO_DELAY_USEC (1000)
+#define MII_MDIO_RETRY_MSEC (10)
struct ipq8064_mdio {
struct regmap *base; /* NSS_GMAC0_BASE */
@@ -65,7 +65,7 @@ ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset)
((reg_offset << MII_REG_SHIFT) & MII_REG_MASK);
regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr);
- usleep_range(8, 10);
+ usleep_range(10, 13);
err = ipq8064_mdio_wait_busy(priv);
if (err)
@@ -91,19 +91,46 @@ ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data)
((reg_offset << MII_REG_SHIFT) & MII_REG_MASK);
regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr);
- usleep_range(8, 10);
+
+ /* For the specific reg 31 extra time is needed or the next
+ * read will produce garbage data.
+ */
+ if (reg_offset == 31)
+ usleep_range(30, 43);
+ else
+ usleep_range(10, 13);
return ipq8064_mdio_wait_busy(priv);
}
+static const struct regmap_config ipq8064_mdio_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .can_multi_write = false,
+ /* the mdio lock is used by any user of this mdio driver */
+ .disable_locking = true,
+
+ .cache_type = REGCACHE_NONE,
+};
+
static int
ipq8064_mdio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct ipq8064_mdio *priv;
+ struct resource res;
struct mii_bus *bus;
+ void __iomem *base;
int ret;
+ if (of_address_to_resource(np, 0, &res))
+ return -ENOMEM;
+
+ base = ioremap(res.start, resource_size(&res));
+ if (!base)
+ return -ENOMEM;
+
bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
if (!bus)
return -ENOMEM;
@@ -115,15 +142,10 @@ ipq8064_mdio_probe(struct platform_device *pdev)
bus->parent = &pdev->dev;
priv = bus->priv;
- priv->base = device_node_to_regmap(np);
- if (IS_ERR(priv->base)) {
- if (priv->base == ERR_PTR(-EPROBE_DEFER))
- return -EPROBE_DEFER;
-
- dev_err(&pdev->dev, "error getting device regmap, error=%pe\n",
- priv->base);
+ priv->base = devm_regmap_init_mmio(&pdev->dev, base,
+ &ipq8064_mdio_regmap_config);
+ if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- }
ret = of_mdiobus_register(bus, np);
if (ret)
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 944ba105cac1..aa985a5aae8d 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -63,6 +63,9 @@
#define DW_VR_MII_DIG_CTRL1 0x8000
#define DW_VR_MII_AN_CTRL 0x8001
#define DW_VR_MII_AN_INTR_STS 0x8002
+/* EEE Mode Control Register */
+#define DW_VR_MII_EEE_MCTRL0 0x8006
+#define DW_VR_MII_EEE_MCTRL1 0x800b
/* VR_MII_DIG_CTRL1 */
#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
@@ -86,6 +89,20 @@
#define DW_VR_MII_C37_ANSGM_SP_1000 0x2
#define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4)
+/* VR MII EEE Control 0 defines */
+#define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */
+#define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */
+#define DW_VR_MII_EEE_TX_QUIET_EN BIT(2) /* Tx Quiet Enable */
+#define DW_VR_MII_EEE_RX_QUIET_EN BIT(3) /* Rx Quiet Enable */
+#define DW_VR_MII_EEE_TX_EN_CTRL BIT(4) /* Tx Control Enable */
+#define DW_VR_MII_EEE_RX_EN_CTRL BIT(7) /* Rx Control Enable */
+
+#define DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT 8
+#define DW_VR_MII_EEE_MULT_FACT_100NS GENMASK(11, 8)
+
+/* VR MII EEE Control 1 defines */
+#define DW_VR_MII_EEE_TRN_LPI BIT(0) /* Transparent Mode Enable */
+
static const int xpcs_usxgmii_features[] = {
ETHTOOL_LINK_MODE_Pause_BIT,
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
@@ -650,6 +667,39 @@ static int xpcs_validate(struct mdio_xpcs_args *xpcs,
return 0;
}
+static int xpcs_config_eee(struct mdio_xpcs_args *xpcs, int mult_fact_100ns,
+ int enable)
+{
+ int ret;
+
+ if (enable) {
+ /* Enable EEE */
+ ret = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
+ DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
+ DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
+ mult_fact_100ns << DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT;
+ } else {
+ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0);
+ if (ret < 0)
+ return ret;
+ ret &= ~(DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
+ DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
+ DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
+ DW_VR_MII_EEE_MULT_FACT_100NS);
+ }
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, ret);
+ if (ret < 0)
+ return ret;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1);
+ if (ret < 0)
+ return ret;
+
+ ret |= DW_VR_MII_EEE_TRN_LPI;
+ return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, ret);
+}
+
static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs)
{
int ret;
@@ -908,6 +958,7 @@ static struct mdio_xpcs_ops xpcs_ops = {
.get_state = xpcs_get_state,
.link_up = xpcs_link_up,
.probe = xpcs_probe,
+ .config_eee = xpcs_config_eee,
};
struct mdio_xpcs_ops *mdio_xpcs_get_ops(void)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 288bf405ebdb..25511f39b01f 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -247,10 +247,11 @@ config NXP_TJA11XX_PHY
Currently supports the NXP TJA1100 and TJA1101 PHY.
config AT803X_PHY
- tristate "Qualcomm Atheros AR803X PHYs"
+ tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
depends on REGULATOR
help
- Currently supports the AR8030, AR8031, AR8033 and AR8035 model
+ Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
+ QCA8337(Internal qca8k PHY) model
config QSEMI_PHY
tristate "Quality Semiconductor PHYs"
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index 55a0b91816e2..5ce6da62cc8e 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
-/**
+/*
* Driver for Analog Devices Industrial Ethernet PHYs
*
* Copyright 2019 Analog Devices Inc.
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 32af52dd5aed..6697c9368b40 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -83,8 +83,8 @@
#define AT803X_MODE_CFG_MASK 0x0F
#define AT803X_MODE_CFG_SGMII 0x01
-#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
-#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
+#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
+#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
#define AT803X_DEBUG_REG_0 0x00
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
@@ -92,10 +92,16 @@
#define AT803X_DEBUG_REG_5 0x05
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
+#define AT803X_DEBUG_REG_3C 0x3C
+
+#define AT803X_DEBUG_REG_3D 0x3D
+
#define AT803X_DEBUG_REG_1F 0x1F
#define AT803X_DEBUG_PLL_ON BIT(2)
#define AT803X_DEBUG_RGMII_1V8 BIT(3)
+#define MDIO_AZ_DEBUG 0x800D
+
/* AT803x supports either the XTAL input pad, an internal PLL or the
* DSP as clock reference for the clock output pad. The XTAL reference
* is only used for 25 MHz output, all other frequencies need the PLL.
@@ -128,33 +134,59 @@
#define AT803X_CLK_OUT_STRENGTH_HALF 1
#define AT803X_CLK_OUT_STRENGTH_QUARTER 2
-#define AT803X_DEFAULT_DOWNSHIFT 5
-#define AT803X_MIN_DOWNSHIFT 2
-#define AT803X_MAX_DOWNSHIFT 9
+#define AT803X_DEFAULT_DOWNSHIFT 5
+#define AT803X_MIN_DOWNSHIFT 2
+#define AT803X_MAX_DOWNSHIFT 9
#define AT803X_MMD3_SMARTEEE_CTL1 0x805b
#define AT803X_MMD3_SMARTEEE_CTL2 0x805c
#define AT803X_MMD3_SMARTEEE_CTL3 0x805d
#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8)
-#define ATH9331_PHY_ID 0x004dd041
-#define ATH8030_PHY_ID 0x004dd076
-#define ATH8031_PHY_ID 0x004dd074
-#define ATH8032_PHY_ID 0x004dd023
-#define ATH8035_PHY_ID 0x004dd072
+#define ATH9331_PHY_ID 0x004dd041
+#define ATH8030_PHY_ID 0x004dd076
+#define ATH8031_PHY_ID 0x004dd074
+#define ATH8032_PHY_ID 0x004dd023
+#define ATH8035_PHY_ID 0x004dd072
#define AT8030_PHY_ID_MASK 0xffffffef
-#define AT803X_PAGE_FIBER 0
-#define AT803X_PAGE_COPPER 1
+#define QCA8327_PHY_ID 0x004dd034
+#define QCA8337_PHY_ID 0x004dd036
+#define QCA8K_PHY_ID_MASK 0xffffffff
+
+#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
+
+#define AT803X_PAGE_FIBER 0
+#define AT803X_PAGE_COPPER 1
+
+/* don't turn off internal PLL */
+#define AT803X_KEEP_PLL_ENABLED BIT(0)
+#define AT803X_DISABLE_SMARTEEE BIT(1)
MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");
+enum stat_access_type {
+ PHY,
+ MMD
+};
+
+struct at803x_hw_stat {
+ const char *string;
+ u8 reg;
+ u32 mask;
+ enum stat_access_type access_type;
+};
+
+static struct at803x_hw_stat at803x_hw_stats[] = {
+ { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
+ { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
+ { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
+};
+
struct at803x_priv {
int flags;
-#define AT803X_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */
-#define AT803X_DISABLE_SMARTEEE BIT(1)
u16 clk_25m_reg;
u16 clk_25m_mask;
u8 smarteee_lpi_tw_1g;
@@ -162,6 +194,7 @@ struct at803x_priv {
struct regulator_dev *vddio_rdev;
struct regulator_dev *vddh_rdev;
struct regulator *vddio;
+ u64 stats[ARRAY_SIZE(at803x_hw_stats)];
};
struct at803x_context {
@@ -173,6 +206,17 @@ struct at803x_context {
u16 led_control;
};
+static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
+{
+ int ret;
+
+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
+ if (ret < 0)
+ return ret;
+
+ return phy_write(phydev, AT803X_DEBUG_DATA, data);
+}
+
static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
{
int ret;
@@ -335,6 +379,53 @@ static void at803x_get_wol(struct phy_device *phydev,
wol->wolopts |= WAKE_MAGIC;
}
+static int at803x_get_sset_count(struct phy_device *phydev)
+{
+ return ARRAY_SIZE(at803x_hw_stats);
+}
+
+static void at803x_get_strings(struct phy_device *phydev, u8 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
+ strscpy(data + i * ETH_GSTRING_LEN,
+ at803x_hw_stats[i].string, ETH_GSTRING_LEN);
+ }
+}
+
+static u64 at803x_get_stat(struct phy_device *phydev, int i)
+{
+ struct at803x_hw_stat stat = at803x_hw_stats[i];
+ struct at803x_priv *priv = phydev->priv;
+ int val;
+ u64 ret;
+
+ if (stat.access_type == MMD)
+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
+ else
+ val = phy_read(phydev, stat.reg);
+
+ if (val < 0) {
+ ret = U64_MAX;
+ } else {
+ val = val & stat.mask;
+ priv->stats[i] += val;
+ ret = priv->stats[i];
+ }
+
+ return ret;
+}
+
+static void at803x_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
+ data[i] = at803x_get_stat(phydev, i);
+}
+
static int at803x_suspend(struct phy_device *phydev)
{
int value;
@@ -1170,6 +1261,34 @@ static int at803x_cable_test_start(struct phy_device *phydev)
return 0;
}
+static int qca83xx_config_init(struct phy_device *phydev)
+{
+ u8 switch_revision;
+
+ switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
+
+ switch (switch_revision) {
+ case 1:
+ /* For 100M waveform */
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea);
+ /* Turn on Gigabit clock */
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0);
+ break;
+
+ case 2:
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
+ fallthrough;
+ case 4:
+ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
+ break;
+ }
+
+ return 0;
+}
+
static struct phy_driver at803x_driver[] = {
{
/* Qualcomm Atheros AR8035 */
@@ -1266,7 +1385,20 @@ static struct phy_driver at803x_driver[] = {
.read_status = at803x_read_status,
.soft_reset = genphy_soft_reset,
.config_aneg = at803x_config_aneg,
-} };
+}, {
+ /* QCA8337 */
+ .phy_id = QCA8337_PHY_ID,
+ .phy_id_mask = QCA8K_PHY_ID_MASK,
+ .name = "QCA PHY 8337",
+ /* PHY_GBIT_FEATURES */
+ .probe = at803x_probe,
+ .flags = PHY_IS_INTERNAL,
+ .config_init = qca83xx_config_init,
+ .soft_reset = genphy_soft_reset,
+ .get_sset_count = at803x_get_sset_count,
+ .get_strings = at803x_get_strings,
+ .get_stats = at803x_get_stats,
+}, };
module_phy_driver(at803x_driver);
diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
index 26b9c0d7cb9d..512e4cb5d2c2 100644
--- a/drivers/net/phy/nxp-c45-tja11xx.c
+++ b/drivers/net/phy/nxp-c45-tja11xx.c
@@ -13,6 +13,9 @@
#include <linux/phy.h>
#include <linux/processor.h>
#include <linux/property.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
#define PHY_ID_TJA_1103 0x001BB010
@@ -57,6 +60,9 @@
#define VEND1_PORT_CONTROL 0x8040
#define PORT_CONTROL_EN BIT(14)
+#define VEND1_PORT_ABILITIES 0x8046
+#define PTP_ABILITY BIT(3)
+
#define VEND1_PORT_INFRA_CONTROL 0xAC00
#define PORT_INFRA_CONTROL_EN BIT(14)
@@ -91,13 +97,106 @@
#define VEND1_TX_IPG_LENGTH 0xAFD1
#define COUNTER_EN BIT(15)
+#define VEND1_LTC_LOAD_CTRL 0x1105
+#define READ_LTC BIT(2)
+#define LOAD_LTC BIT(0)
+
+#define VEND1_LTC_WR_NSEC_0 0x1106
+#define VEND1_LTC_WR_NSEC_1 0x1107
+#define VEND1_LTC_WR_SEC_0 0x1108
+#define VEND1_LTC_WR_SEC_1 0x1109
+
+#define VEND1_LTC_RD_NSEC_0 0x110A
+#define VEND1_LTC_RD_NSEC_1 0x110B
+#define VEND1_LTC_RD_SEC_0 0x110C
+#define VEND1_LTC_RD_SEC_1 0x110D
+
+#define VEND1_RATE_ADJ_SUBNS_0 0x110F
+#define VEND1_RATE_ADJ_SUBNS_1 0x1110
+#define CLK_RATE_ADJ_LD BIT(15)
+#define CLK_RATE_ADJ_DIR BIT(14)
+
+#define VEND1_HW_LTC_LOCK_CTRL 0x1115
+#define HW_LTC_LOCK_EN BIT(0)
+
+#define VEND1_PTP_IRQ_EN 0x1131
+#define VEND1_PTP_IRQ_STATUS 0x1132
+#define PTP_IRQ_EGR_TS BIT(0)
+
+#define VEND1_RX_TS_INSRT_CTRL 0x114D
+#define RX_TS_INSRT_MODE2 0x02
+
+#define VEND1_EGR_RING_DATA_0 0x114E
+#define VEND1_EGR_RING_DATA_1_SEQ_ID 0x114F
+#define VEND1_EGR_RING_DATA_2_NSEC_15_0 0x1150
+#define VEND1_EGR_RING_DATA_3 0x1151
+#define VEND1_EGR_RING_CTRL 0x1154
+
+#define RING_DATA_0_DOMAIN_NUMBER GENMASK(7, 0)
+#define RING_DATA_0_MSG_TYPE GENMASK(11, 8)
+#define RING_DATA_0_SEC_4_2 GENMASK(14, 2)
+#define RING_DATA_0_TS_VALID BIT(15)
+
+#define RING_DATA_3_NSEC_29_16 GENMASK(13, 0)
+#define RING_DATA_3_SEC_1_0 GENMASK(15, 14)
+#define RING_DATA_5_SEC_16_5 GENMASK(15, 4)
+#define RING_DONE BIT(0)
+
+#define TS_SEC_MASK GENMASK(1, 0)
+
+#define VEND1_PORT_FUNC_ENABLES 0x8048
+#define PTP_ENABLE BIT(3)
+
+#define VEND1_PORT_PTP_CONTROL 0x9000
+#define PORT_PTP_CONTROL_BYPASS BIT(11)
+
+#define VEND1_PTP_CLK_PERIOD 0x1104
+#define PTP_CLK_PERIOD_100BT1 15ULL
+
+#define VEND1_EVENT_MSG_FILT 0x1148
+#define EVENT_MSG_FILT_ALL 0x0F
+#define EVENT_MSG_FILT_NONE 0x00
+
+#define VEND1_TX_PIPE_DLY_NS 0x1149
+#define VEND1_TX_PIPEDLY_SUBNS 0x114A
+#define VEND1_RX_PIPE_DLY_NS 0x114B
+#define VEND1_RX_PIPEDLY_SUBNS 0x114C
+
#define RGMII_PERIOD_PS 8000U
#define PS_PER_DEGREE div_u64(RGMII_PERIOD_PS, 360)
#define MIN_ID_PS 1644U
#define MAX_ID_PS 2260U
#define DEFAULT_ID_PS 2000U
+#define PPM_TO_SUBNS_INC(ppb) div_u64(GENMASK(31, 0) * (ppb) * \
+ PTP_CLK_PERIOD_100BT1, NSEC_PER_SEC)
+
+#define NXP_C45_SKB_CB(skb) ((struct nxp_c45_skb_cb *)(skb)->cb)
+
+struct nxp_c45_skb_cb {
+ struct ptp_header *header;
+ unsigned int type;
+};
+
+struct nxp_c45_hwts {
+ u32 nsec;
+ u32 sec;
+ u8 domain_number;
+ u16 sequence_id;
+ u8 msg_type;
+};
+
struct nxp_c45_phy {
+ struct phy_device *phydev;
+ struct mii_timestamper mii_ts;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info caps;
+ struct sk_buff_head tx_queue;
+ struct sk_buff_head rx_queue;
+ /* used to access the PTP registers atomic */
+ struct mutex ptp_lock;
+ int hwts_tx;
+ int hwts_rx;
u32 tx_delay;
u32 rx_delay;
};
@@ -110,6 +209,382 @@ struct nxp_c45_phy_stats {
u16 mask;
};
+static bool nxp_c45_poll_txts(struct phy_device *phydev)
+{
+ return phydev->irq <= 0;
+}
+
+static int _nxp_c45_ptp_gettimex64(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL,
+ READ_LTC);
+ ts->tv_nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_LTC_RD_NSEC_0);
+ ts->tv_nsec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_LTC_RD_NSEC_1) << 16;
+ ts->tv_sec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_LTC_RD_SEC_0);
+ ts->tv_sec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_LTC_RD_SEC_1) << 16;
+
+ return 0;
+}
+
+static int nxp_c45_ptp_gettimex64(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+
+ mutex_lock(&priv->ptp_lock);
+ _nxp_c45_ptp_gettimex64(ptp, ts, sts);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int _nxp_c45_ptp_settime64(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_0,
+ ts->tv_nsec);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_1,
+ ts->tv_nsec >> 16);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_0,
+ ts->tv_sec);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_1,
+ ts->tv_sec >> 16);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL,
+ LOAD_LTC);
+
+ return 0;
+}
+
+static int nxp_c45_ptp_settime64(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+
+ mutex_lock(&priv->ptp_lock);
+ _nxp_c45_ptp_settime64(ptp, ts);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int nxp_c45_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
+ u64 subns_inc_val;
+ bool inc;
+
+ mutex_lock(&priv->ptp_lock);
+ inc = ppb >= 0;
+ ppb = abs(ppb);
+
+ subns_inc_val = PPM_TO_SUBNS_INC(ppb);
+
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_0,
+ subns_inc_val);
+ subns_inc_val >>= 16;
+ subns_inc_val |= CLK_RATE_ADJ_LD;
+ if (inc)
+ subns_inc_val |= CLK_RATE_ADJ_DIR;
+
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_1,
+ subns_inc_val);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int nxp_c45_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ struct timespec64 now, then;
+
+ mutex_lock(&priv->ptp_lock);
+ then = ns_to_timespec64(delta);
+ _nxp_c45_ptp_gettimex64(ptp, &now, NULL);
+ now = timespec64_add(now, then);
+ _nxp_c45_ptp_settime64(ptp, &now);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static void nxp_c45_reconstruct_ts(struct timespec64 *ts,
+ struct nxp_c45_hwts *hwts)
+{
+ ts->tv_nsec = hwts->nsec;
+ if ((ts->tv_sec & TS_SEC_MASK) < (hwts->sec & TS_SEC_MASK))
+ ts->tv_sec -= BIT(2);
+ ts->tv_sec &= ~TS_SEC_MASK;
+ ts->tv_sec |= hwts->sec & TS_SEC_MASK;
+}
+
+static bool nxp_c45_match_ts(struct ptp_header *header,
+ struct nxp_c45_hwts *hwts,
+ unsigned int type)
+{
+ return ntohs(header->sequence_id) == hwts->sequence_id &&
+ ptp_get_msgtype(header, type) == hwts->msg_type &&
+ header->domain_number == hwts->domain_number;
+}
+
+static bool nxp_c45_get_hwtxts(struct nxp_c45_phy *priv,
+ struct nxp_c45_hwts *hwts)
+{
+ bool valid;
+ u16 reg;
+
+ mutex_lock(&priv->ptp_lock);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_CTRL,
+ RING_DONE);
+ reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_0);
+ valid = !!(reg & RING_DATA_0_TS_VALID);
+ if (!valid)
+ goto nxp_c45_get_hwtxts_out;
+
+ hwts->domain_number = reg;
+ hwts->msg_type = (reg & RING_DATA_0_MSG_TYPE) >> 8;
+ hwts->sec = (reg & RING_DATA_0_SEC_4_2) >> 10;
+ hwts->sequence_id = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_EGR_RING_DATA_1_SEQ_ID);
+ hwts->nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_EGR_RING_DATA_2_NSEC_15_0);
+ reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_3);
+ hwts->nsec |= (reg & RING_DATA_3_NSEC_29_16) << 16;
+ hwts->sec |= (reg & RING_DATA_3_SEC_1_0) >> 14;
+
+nxp_c45_get_hwtxts_out:
+ mutex_unlock(&priv->ptp_lock);
+ return valid;
+}
+
+static void nxp_c45_process_txts(struct nxp_c45_phy *priv,
+ struct nxp_c45_hwts *txts)
+{
+ struct sk_buff *skb, *tmp, *skb_match = NULL;
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct timespec64 ts;
+ unsigned long flags;
+ bool ts_match;
+ s64 ts_ns;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ skb_queue_walk_safe(&priv->tx_queue, skb, tmp) {
+ ts_match = nxp_c45_match_ts(NXP_C45_SKB_CB(skb)->header, txts,
+ NXP_C45_SKB_CB(skb)->type);
+ if (!ts_match)
+ continue;
+ skb_match = skb;
+ __skb_unlink(skb, &priv->tx_queue);
+ break;
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
+ if (skb_match) {
+ nxp_c45_ptp_gettimex64(&priv->caps, &ts, NULL);
+ nxp_c45_reconstruct_ts(&ts, txts);
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ ts_ns = timespec64_to_ns(&ts);
+ shhwtstamps.hwtstamp = ns_to_ktime(ts_ns);
+ skb_complete_tx_timestamp(skb_match, &shhwtstamps);
+ } else {
+ phydev_warn(priv->phydev,
+ "the tx timestamp doesn't match with any skb\n");
+ }
+}
+
+static long nxp_c45_do_aux_work(struct ptp_clock_info *ptp)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ bool poll_txts = nxp_c45_poll_txts(priv->phydev);
+ struct skb_shared_hwtstamps *shhwtstamps_rx;
+ struct nxp_c45_hwts hwts;
+ bool reschedule = false;
+ struct timespec64 ts;
+ struct sk_buff *skb;
+ bool txts_valid;
+ u32 ts_raw;
+
+ while (!skb_queue_empty_lockless(&priv->tx_queue) && poll_txts) {
+ txts_valid = nxp_c45_get_hwtxts(priv, &hwts);
+ if (unlikely(!txts_valid)) {
+ /* Still more skbs in the queue */
+ reschedule = true;
+ break;
+ }
+
+ nxp_c45_process_txts(priv, &hwts);
+ }
+
+ nxp_c45_ptp_gettimex64(&priv->caps, &ts, NULL);
+ while ((skb = skb_dequeue(&priv->rx_queue)) != NULL) {
+ ts_raw = __be32_to_cpu(NXP_C45_SKB_CB(skb)->header->reserved2);
+ hwts.sec = ts_raw >> 30;
+ hwts.nsec = ts_raw & GENMASK(29, 0);
+ nxp_c45_reconstruct_ts(&ts, &hwts);
+ shhwtstamps_rx = skb_hwtstamps(skb);
+ shhwtstamps_rx->hwtstamp = ns_to_ktime(timespec64_to_ns(&ts));
+ NXP_C45_SKB_CB(skb)->header->reserved2 = 0;
+ netif_rx_ni(skb);
+ }
+
+ return reschedule ? 1 : -1;
+}
+
+static int nxp_c45_init_ptp_clock(struct nxp_c45_phy *priv)
+{
+ priv->caps = (struct ptp_clock_info) {
+ .owner = THIS_MODULE,
+ .name = "NXP C45 PHC",
+ .max_adj = 16666666,
+ .adjfine = nxp_c45_ptp_adjfine,
+ .adjtime = nxp_c45_ptp_adjtime,
+ .gettimex64 = nxp_c45_ptp_gettimex64,
+ .settime64 = nxp_c45_ptp_settime64,
+ .do_aux_work = nxp_c45_do_aux_work,
+ };
+
+ priv->ptp_clock = ptp_clock_register(&priv->caps,
+ &priv->phydev->mdio.dev);
+
+ if (IS_ERR(priv->ptp_clock))
+ return PTR_ERR(priv->ptp_clock);
+
+ if (!priv->ptp_clock)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void nxp_c45_txtstamp(struct mii_timestamper *mii_ts,
+ struct sk_buff *skb, int type)
+{
+ struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
+ mii_ts);
+
+ switch (priv->hwts_tx) {
+ case HWTSTAMP_TX_ON:
+ NXP_C45_SKB_CB(skb)->type = type;
+ NXP_C45_SKB_CB(skb)->header = ptp_parse_header(skb, type);
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ skb_queue_tail(&priv->tx_queue, skb);
+ if (nxp_c45_poll_txts(priv->phydev))
+ ptp_schedule_worker(priv->ptp_clock, 0);
+ break;
+ case HWTSTAMP_TX_OFF:
+ default:
+ kfree_skb(skb);
+ break;
+ }
+}
+
+static bool nxp_c45_rxtstamp(struct mii_timestamper *mii_ts,
+ struct sk_buff *skb, int type)
+{
+ struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
+ mii_ts);
+ struct ptp_header *header = ptp_parse_header(skb, type);
+
+ if (!header)
+ return false;
+
+ if (!priv->hwts_rx)
+ return false;
+
+ NXP_C45_SKB_CB(skb)->header = header;
+ skb_queue_tail(&priv->rx_queue, skb);
+ ptp_schedule_worker(priv->ptp_clock, 0);
+
+ return true;
+}
+
+static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts,
+ struct ifreq *ifreq)
+{
+ struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
+ mii_ts);
+ struct phy_device *phydev = priv->phydev;
+ struct hwtstamp_config cfg;
+
+ if (copy_from_user(&cfg, ifreq->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ON)
+ return -ERANGE;
+
+ priv->hwts_tx = cfg.tx_type;
+
+ switch (cfg.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ priv->hwts_rx = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ priv->hwts_rx = 1;
+ cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (priv->hwts_rx || priv->hwts_tx) {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT,
+ EVENT_MSG_FILT_ALL);
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_PTP_CONTROL,
+ PORT_PTP_CONTROL_BYPASS);
+ } else {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT,
+ EVENT_MSG_FILT_NONE);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_PTP_CONTROL,
+ PORT_PTP_CONTROL_BYPASS);
+ }
+
+ if (nxp_c45_poll_txts(priv->phydev))
+ goto nxp_c45_no_ptp_irq;
+
+ if (priv->hwts_tx)
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS);
+ else
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS);
+
+nxp_c45_no_ptp_irq:
+ return copy_to_user(ifreq->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+static int nxp_c45_ts_info(struct mii_timestamper *mii_ts,
+ struct ethtool_ts_info *ts_info)
+{
+ struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
+ mii_ts);
+
+ ts_info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ ts_info->phc_index = ptp_clock_index(priv->ptp_clock);
+ ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+ ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
+
+ return 0;
+}
+
static const struct nxp_c45_phy_stats nxp_c45_hw_stats[] = {
{ "phy_symbol_error_cnt", MDIO_MMD_VEND1,
VEND1_SYMBOL_ERROR_COUNTER, 0, GENMASK(15, 0) },
@@ -205,7 +680,9 @@ static int nxp_c45_config_intr(struct phy_device *phydev)
static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev)
{
+ struct nxp_c45_phy *priv = phydev->priv;
irqreturn_t ret = IRQ_NONE;
+ struct nxp_c45_hwts hwts;
int irq;
irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_IRQ_STATUS);
@@ -216,6 +693,18 @@ static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev)
ret = IRQ_HANDLED;
}
+ /* There is no need for ACK.
+ * The irq signal will be asserted until the EGR TS FIFO will be
+ * emptied.
+ */
+ irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_IRQ_STATUS);
+ if (irq & PTP_IRQ_EGR_TS) {
+ while (nxp_c45_get_hwtxts(priv, &hwts))
+ nxp_c45_process_txts(priv, &hwts);
+
+ ret = IRQ_HANDLED;
+ }
+
return ret;
}
@@ -566,20 +1055,60 @@ static int nxp_c45_config_init(struct phy_device *phydev)
phydev->autoneg = AUTONEG_DISABLE;
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK_PERIOD,
+ PTP_CLK_PERIOD_100BT1);
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_HW_LTC_LOCK_CTRL,
+ HW_LTC_LOCK_EN);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_TS_INSRT_CTRL,
+ RX_TS_INSRT_MODE2);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES,
+ PTP_ENABLE);
+
return nxp_c45_start_op(phydev);
}
static int nxp_c45_probe(struct phy_device *phydev)
{
struct nxp_c45_phy *priv;
+ int ptp_ability;
+ int ret = 0;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ skb_queue_head_init(&priv->tx_queue);
+ skb_queue_head_init(&priv->rx_queue);
+
+ priv->phydev = phydev;
+
phydev->priv = priv;
- return 0;
+ mutex_init(&priv->ptp_lock);
+
+ ptp_ability = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_ABILITIES);
+ ptp_ability = !!(ptp_ability & PTP_ABILITY);
+ if (!ptp_ability) {
+ phydev_info(phydev, "the phy does not support PTP");
+ goto no_ptp_support;
+ }
+
+ if (IS_ENABLED(CONFIG_PTP_1588_CLOCK) &&
+ IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING)) {
+ priv->mii_ts.rxtstamp = nxp_c45_rxtstamp;
+ priv->mii_ts.txtstamp = nxp_c45_txtstamp;
+ priv->mii_ts.hwtstamp = nxp_c45_hwtstamp;
+ priv->mii_ts.ts_info = nxp_c45_ts_info;
+ phydev->mii_ts = &priv->mii_ts;
+ ret = nxp_c45_init_ptp_clock(priv);
+ } else {
+ phydev_dbg(phydev, "PTP support not enabled even if the phy supports it");
+ }
+
+no_ptp_support:
+
+ return ret;
}
static struct phy_driver nxp_c45_driver[] = {
diff --git a/drivers/net/phy/rockchip.c b/drivers/net/phy/rockchip.c
index 52f1f65320fe..bb13e75183ee 100644
--- a/drivers/net/phy/rockchip.c
+++ b/drivers/net/phy/rockchip.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
-/**
+/*
* drivers/net/phy/rockchip.c
*
* Driver for ROCKCHIP Ethernet PHYs
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 84f832806313..2ced021f4faf 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2559,15 +2559,15 @@ static int tun_flags(struct tun_struct *tun)
return tun->flags & (TUN_FEATURES | IFF_PERSIST | IFF_TUN | IFF_TAP);
}
-static ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr,
+static ssize_t tun_flags_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tun_struct *tun = netdev_priv(to_net_dev(dev));
return sprintf(buf, "0x%x\n", tun_flags(tun));
}
-static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t owner_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct tun_struct *tun = netdev_priv(to_net_dev(dev));
return uid_valid(tun->owner)?
@@ -2576,8 +2576,8 @@ static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr,
sprintf(buf, "-1\n");
}
-static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t group_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct tun_struct *tun = netdev_priv(to_net_dev(dev));
return gid_valid(tun->group) ?
@@ -2586,9 +2586,9 @@ static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr,
sprintf(buf, "-1\n");
}
-static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL);
-static DEVICE_ATTR(owner, 0444, tun_show_owner, NULL);
-static DEVICE_ATTR(group, 0444, tun_show_group, NULL);
+static DEVICE_ATTR_RO(tun_flags);
+static DEVICE_ATTR_RO(owner);
+static DEVICE_ATTR_RO(group);
static struct attribute *tun_dev_attrs[] = {
&dev_attr_tun_flags.attr,
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index fbbe78643631..179308782888 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -169,7 +169,7 @@ config USB_NET_AX8817X
This option adds support for ASIX AX88xxx based USB 2.0
10/100 Ethernet adapters.
- This driver should work with at least the following devices:
+ This driver should work with at least the following devices:
* Aten UC210T
* ASIX AX88172
* Billionton Systems, USB2AR
@@ -220,13 +220,13 @@ config USB_NET_CDCETHER
CDC Ethernet is an implementation option for DOCSIS cable modems
that support USB connectivity, used for non-Microsoft USB hosts.
The Linux-USB CDC Ethernet Gadget driver is an open implementation.
- This driver should work with at least the following devices:
+ This driver should work with at least the following devices:
* Dell Wireless 5530 HSPA
- * Ericsson PipeRider (all variants)
+ * Ericsson PipeRider (all variants)
* Ericsson Mobile Broadband Module (all variants)
- * Motorola (DM100 and SB4100)
- * Broadcom Cable Modem (reference design)
+ * Motorola (DM100 and SB4100)
+ * Broadcom Cable Modem (reference design)
* Toshiba (PCX1100U and F3507g/F3607gw)
* ...
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 5db66272fc82..42fb75057c15 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -168,6 +168,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
subdriver = usb_cdc_wdm_register(ctx->control,
&dev->status->desc,
le16_to_cpu(ctx->mbim_desc->wMaxControlMessage),
+ WWAN_PORT_MBIM,
cdc_mbim_wdm_manage_power);
if (IS_ERR(subdriver)) {
ret = PTR_ERR(subdriver);
diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c
index a87f0dabcdb7..849b77330bf2 100644
--- a/drivers/net/usb/huawei_cdc_ncm.c
+++ b/drivers/net/usb/huawei_cdc_ncm.c
@@ -96,6 +96,7 @@ static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev,
subdriver = usb_cdc_wdm_register(ctx->control,
&usbnet_dev->status->desc,
1024, /* wMaxCommand */
+ WWAN_PORT_AT,
huawei_cdc_ncm_wdm_manage_power);
if (IS_ERR(subdriver)) {
ret = PTR_ERR(subdriver);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 6700f1970b24..db157f21a322 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -710,7 +710,8 @@ static int qmi_wwan_register_subdriver(struct usbnet *dev)
/* register subdriver */
subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc,
- 4096, &qmi_wwan_cdc_wdm_manage_power);
+ 4096, WWAN_PORT_QMI,
+ &qmi_wwan_cdc_wdm_manage_power);
if (IS_ERR(subdriver)) {
dev_err(&info->control->dev, "subdriver registration failed\n");
rv = PTR_ERR(subdriver);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 9b6a4a875c55..073fec4c0df1 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -380,7 +380,7 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
bool hdr_valid, unsigned int metasize,
- unsigned int headroom)
+ bool whole_page)
{
struct sk_buff *skb;
struct virtio_net_hdr_mrg_rxbuf *hdr;
@@ -398,17 +398,21 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
else
hdr_padded_len = sizeof(struct padded_vnet_hdr);
- /* If headroom is not 0, there is an offset between the beginning of the
+ /* If whole_page, there is an offset between the beginning of the
* data and the allocated space, otherwise the data and the allocated
* space are aligned.
*/
- if (headroom) {
- /* Buffers with headroom use PAGE_SIZE as alloc size,
+ if (whole_page) {
+ /* Buffers with whole_page use PAGE_SIZE as alloc size,
* see add_recvbuf_mergeable() + get_mergeable_buf_len()
*/
truesize = PAGE_SIZE;
- tailroom = truesize - len - offset;
- buf = page_address(page);
+
+ /* page maybe head page, so we should get the buf by p, not the
+ * page
+ */
+ tailroom = truesize - len - offset_in_page(p);
+ buf = (char *)((unsigned long)p & PAGE_MASK);
} else {
tailroom = truesize - len;
buf = p;
@@ -958,7 +962,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
put_page(page);
head_skb = page_to_skb(vi, rq, xdp_page, offset,
len, PAGE_SIZE, false,
- metasize, headroom);
+ metasize, true);
return head_skb;
}
break;
@@ -1016,7 +1020,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
}
head_skb = page_to_skb(vi, rq, page, offset, len, truesize, !xdp_prog,
- metasize, headroom);
+ metasize, !!headroom);
curr_skb = head_skb;
if (unlikely(!curr_skb))
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 83c9481995dd..473df2505c8e 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -49,7 +49,7 @@ config COSA
network device.
You will need user-space utilities COSA or SRP boards for downloading
- the firmware to the cards and to set them up. Look at the
+ the firmware to the cards and to set them up. Look at the
<http://www.fi.muni.cz/~kas/cosa/> for more information. You can also
read the comment at the top of the <file:drivers/net/wan/cosa.c> for
details about the cards and the driver itself.
@@ -108,7 +108,7 @@ config HDLC
Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame
Relay, synchronous Point-to-Point Protocol (PPP) and X.25.
- To compile this driver as a module, choose M here: the
+ To compile this driver as a module, choose M here: the
module will be called hdlc.
If unsure, say N.
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index c354a5143e99..7e431e5b6e85 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -28,9 +28,8 @@
#include "hd64570.h"
-
-static const char* version = "Moxa C101 driver version: 1.15";
-static const char* devname = "C101";
+static const char *version = "Moxa C101 driver version: 1.15";
+static const char *devname = "C101";
#undef DEBUG_PKT
#define DEBUG_RINGS
@@ -51,7 +50,6 @@ static const char* devname = "C101";
static char *hw; /* pointer to hw=xxx command line string */
-
typedef struct card_s {
struct net_device *dev;
spinlock_t lock; /* TX lock */
@@ -72,14 +70,13 @@ typedef struct card_s {
u8 page;
struct card_s *next_card;
-}card_t;
+} card_t;
typedef card_t port_t;
static card_t *first_card;
static card_t **new_card = &first_card;
-
#define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg))
#define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg))
#define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg))
@@ -87,8 +84,8 @@ static card_t **new_card = &first_card;
/* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */
#define sca_outw(value, reg, card) do { \
writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \
- writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\
-} while(0)
+ writeb((value >> 8) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\
+} while (0)
#define port_to_card(port) (port)
#define log_node(port) (0)
@@ -99,7 +96,6 @@ static card_t **new_card = &first_card;
#define get_port(card, port) (card)
static void sca_msci_intr(port_t *port);
-
static inline u8 sca_get_page(card_t *card)
{
return card->page;
@@ -111,10 +107,8 @@ static inline void openwin(card_t *card, u8 page)
writeb(page, card->win0base + C101_PAGE);
}
-
#include "hd64570.c"
-
static inline void set_carrier(port_t *port)
{
if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD))
@@ -123,7 +117,6 @@ static inline void set_carrier(port_t *port)
netif_carrier_off(port_to_dev(port));
}
-
static void sca_msci_intr(port_t *port)
{
u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */
@@ -145,13 +138,12 @@ static void sca_msci_intr(port_t *port)
set_carrier(port);
}
-
static void c101_set_iface(port_t *port)
{
u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK;
- switch(port->settings.clock_type) {
+ switch (port->settings.clock_type) {
case CLOCK_INT:
rxs |= CLK_BRG_RX; /* TX clock */
txs |= CLK_RXCLK_TX; /* BRG output */
@@ -179,7 +171,6 @@ static void c101_set_iface(port_t *port)
sca_set_port(port);
}
-
static int c101_open(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
@@ -206,7 +197,6 @@ static int c101_open(struct net_device *dev)
return 0;
}
-
static int c101_close(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
@@ -218,7 +208,6 @@ static int c101_close(struct net_device *dev)
return 0;
}
-
static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
const size_t size = sizeof(sync_serial_settings);
@@ -240,7 +229,7 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (cmd != SIOCWANDEV)
return hdlc_ioctl(dev, ifr, cmd);
- switch(ifr->ifr_settings.type) {
+ switch (ifr->ifr_settings.type) {
case IF_GET_IFACE:
ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
if (ifr->ifr_settings.size < size) {
@@ -252,7 +241,7 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return 0;
case IF_IFACE_SYNC_SERIAL:
- if(!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&new_line, line, size))
@@ -276,8 +265,6 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
}
-
-
static void c101_destroy_card(card_t *card)
{
readb(card->win0base + C101_PAGE); /* Resets SCA? */
@@ -309,12 +296,12 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
card_t *card;
int result;
- if (irq<3 || irq>15 || irq == 6) /* FIXME */ {
+ if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ {
pr_err("invalid IRQ value\n");
return -ENODEV;
}
- if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) {
+ if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) != 0) {
pr_err("invalid RAM value\n");
return -ENODEV;
}
@@ -392,8 +379,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
return 0;
}
-
-
static int __init c101_init(void)
{
if (hw == NULL) {
@@ -419,13 +404,12 @@ static int __init c101_init(void)
if (*hw == '\x0')
return first_card ? 0 : -EINVAL;
- }while(*hw++ == ':');
+ } while (*hw++ == ':');
pr_err("invalid hardware parameters\n");
return first_card ? 0 : -EINVAL;
}
-
static void __exit c101_cleanup(void)
{
card_t *card = first_card;
@@ -438,7 +422,6 @@ static void __exit c101_cleanup(void)
}
}
-
module_init(c101_init);
module_exit(c101_cleanup);
diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c
index 7eac6a3e1cde..39f05fabbfa4 100644
--- a/drivers/net/wan/fsl_ucc_hdlc.c
+++ b/drivers/net/wan/fsl_ucc_hdlc.c
@@ -1171,9 +1171,8 @@ static int ucc_hdlc_probe(struct platform_device *pdev)
ut_info->uf_info.irq = irq_of_parse_and_map(np, 0);
uhdlc_priv = kzalloc(sizeof(*uhdlc_priv), GFP_KERNEL);
- if (!uhdlc_priv) {
+ if (!uhdlc_priv)
return -ENOMEM;
- }
dev_set_drvdata(&pdev->dev, uhdlc_priv);
uhdlc_priv->dev = &pdev->dev;
diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c
index cff04e532c1e..92a8a6ffc567 100644
--- a/drivers/net/wwan/wwan_core.c
+++ b/drivers/net/wwan/wwan_core.c
@@ -169,6 +169,30 @@ static void wwan_remove_dev(struct wwan_device *wwandev)
/* ------- WWAN port management ------- */
+/* Keep aligned with wwan_port_type enum */
+static const char * const wwan_port_type_str[] = {
+ "AT",
+ "MBIM",
+ "QMI",
+ "QCDM",
+ "FIREHOSE"
+};
+
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct wwan_port *port = to_wwan_port(dev);
+
+ return sprintf(buf, "%s\n", wwan_port_type_str[port->type]);
+}
+static DEVICE_ATTR_RO(type);
+
+static struct attribute *wwan_port_attrs[] = {
+ &dev_attr_type.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(wwan_port);
+
static void wwan_port_destroy(struct device *dev)
{
struct wwan_port *port = to_wwan_port(dev);
@@ -182,6 +206,7 @@ static void wwan_port_destroy(struct device *dev)
static const struct device_type wwan_port_dev_type = {
.name = "wwan_port",
.release = wwan_port_destroy,
+ .groups = wwan_port_groups,
};
static int wwan_port_minor_match(struct device *dev, const void *minor)
@@ -201,15 +226,6 @@ static struct wwan_port *wwan_port_get_by_minor(unsigned int minor)
return to_wwan_port(dev);
}
-/* Keep aligned with wwan_port_type enum */
-static const char * const wwan_port_type_str[] = {
- "AT",
- "MBIM",
- "QMI",
- "QCDM",
- "FIREHOSE"
-};
-
struct wwan_port *wwan_create_port(struct device *parent,
enum wwan_port_type type,
const struct wwan_port_ops *ops,
diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c
index 897394167522..38b8d6cab593 100644
--- a/drivers/nfc/s3fwrn5/i2c.c
+++ b/drivers/nfc/s3fwrn5/i2c.c
@@ -6,6 +6,7 @@
* Robert Baldyga <[email protected]>
*/
+#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/delay.h>
@@ -22,6 +23,7 @@
struct s3fwrn5_i2c_phy {
struct phy_common common;
struct i2c_client *i2c_dev;
+ struct clk *clk;
unsigned int irq_skip:1;
};
@@ -207,17 +209,40 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client,
if (ret < 0)
return ret;
+ phy->clk = devm_clk_get_optional(&client->dev, NULL);
+ if (IS_ERR(phy->clk))
+ return dev_err_probe(&client->dev, PTR_ERR(phy->clk),
+ "failed to get clock\n");
+
+ /*
+ * S3FWRN5 depends on a clock input ("XI" pin) to function properly.
+ * Depending on the hardware configuration this could be an always-on
+ * oscillator or some external clock that must be explicitly enabled.
+ * Make sure the clock is running before starting S3FWRN5.
+ */
+ ret = clk_prepare_enable(phy->clk);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
ret = s3fwrn5_probe(&phy->common.ndev, phy, &phy->i2c_dev->dev,
&i2c_phy_ops);
if (ret < 0)
- return ret;
+ goto disable_clk;
ret = devm_request_threaded_irq(&client->dev, phy->i2c_dev->irq, NULL,
s3fwrn5_i2c_irq_thread_fn, IRQF_ONESHOT,
S3FWRN5_I2C_DRIVER_NAME, phy);
if (ret)
- s3fwrn5_remove(phy->common.ndev);
+ goto s3fwrn5_remove;
+ return 0;
+
+s3fwrn5_remove:
+ s3fwrn5_remove(phy->common.ndev);
+disable_clk:
+ clk_disable_unprepare(phy->clk);
return ret;
}
@@ -226,6 +251,7 @@ static int s3fwrn5_i2c_remove(struct i2c_client *client)
struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client);
s3fwrn5_remove(phy->common.ndev);
+ clk_disable_unprepare(phy->clk);
return 0;
}
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 03a246e60fd9..a780435331c8 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -63,27 +63,6 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
spin_unlock_irqrestore(&queue->lock, flags);
}
-s32 scaled_ppm_to_ppb(long ppm)
-{
- /*
- * The 'freq' field in the 'struct timex' is in parts per
- * million, but with a 16 bit binary fractional field.
- *
- * We want to calculate
- *
- * ppb = scaled_ppm * 1000 / 2^16
- *
- * which simplifies to
- *
- * ppb = scaled_ppm * 125 / 2^13
- */
- s64 ppb = 1 + ppm;
- ppb *= 125;
- ppb >>= 13;
- return (s32) ppb;
-}
-EXPORT_SYMBOL(scaled_ppm_to_ppb);
-
/* posix clock implementation */
static int ptp_clock_getres(struct posix_clock *pc, struct timespec64 *tp)
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 508b1c3f8b73..457b00c6e984 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -21,8 +21,10 @@
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/poll.h>
+#include <linux/skbuff.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
+#include <linux/wwan.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <linux/usb/cdc-wdm.h>
@@ -55,6 +57,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_SUSPENDING 8
#define WDM_RESETTING 9
#define WDM_OVERFLOW 10
+#define WDM_WWAN_IN_USE 11
#define WDM_MAX 16
@@ -106,6 +109,9 @@ struct wdm_device {
struct list_head device_list;
int (*manage_power)(struct usb_interface *, int);
+
+ enum wwan_port_type wwanp_type;
+ struct wwan_port *wwanp;
};
static struct usb_driver wdm_driver;
@@ -157,6 +163,8 @@ static void wdm_out_callback(struct urb *urb)
wake_up_all(&desc->wait);
}
+static void wdm_wwan_rx(struct wdm_device *desc, int length);
+
static void wdm_in_callback(struct urb *urb)
{
unsigned long flags;
@@ -192,6 +200,11 @@ static void wdm_in_callback(struct urb *urb)
}
}
+ if (test_bit(WDM_WWAN_IN_USE, &desc->flags)) {
+ wdm_wwan_rx(desc, length);
+ goto out;
+ }
+
/*
* only set a new error if there is no previous error.
* Errors are only cleared during read/open
@@ -226,6 +239,7 @@ skip_error:
set_bit(WDM_READ, &desc->flags);
wake_up(&desc->wait);
}
+out:
spin_unlock_irqrestore(&desc->iuspin, flags);
}
@@ -697,6 +711,11 @@ static int wdm_open(struct inode *inode, struct file *file)
goto out;
file->private_data = desc;
+ if (test_bit(WDM_WWAN_IN_USE, &desc->flags)) {
+ rv = -EBUSY;
+ goto out;
+ }
+
rv = usb_autopm_get_interface(desc->intf);
if (rv < 0) {
dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
@@ -792,6 +811,151 @@ static struct usb_class_driver wdm_class = {
.minor_base = WDM_MINOR_BASE,
};
+/* --- WWAN framework integration --- */
+#ifdef CONFIG_WWAN
+static int wdm_wwan_port_start(struct wwan_port *port)
+{
+ struct wdm_device *desc = wwan_port_get_drvdata(port);
+
+ /* The interface is both exposed via the WWAN framework and as a
+ * legacy usbmisc chardev. If chardev is already open, just fail
+ * to prevent concurrent usage. Otherwise, switch to WWAN mode.
+ */
+ mutex_lock(&wdm_mutex);
+ if (desc->count) {
+ mutex_unlock(&wdm_mutex);
+ return -EBUSY;
+ }
+ set_bit(WDM_WWAN_IN_USE, &desc->flags);
+ mutex_unlock(&wdm_mutex);
+
+ desc->manage_power(desc->intf, 1);
+
+ /* tx is allowed */
+ wwan_port_txon(port);
+
+ /* Start getting events */
+ return usb_submit_urb(desc->validity, GFP_KERNEL);
+}
+
+static void wdm_wwan_port_stop(struct wwan_port *port)
+{
+ struct wdm_device *desc = wwan_port_get_drvdata(port);
+
+ /* Stop all transfers and disable WWAN mode */
+ kill_urbs(desc);
+ desc->manage_power(desc->intf, 0);
+ clear_bit(WDM_READ, &desc->flags);
+ clear_bit(WDM_WWAN_IN_USE, &desc->flags);
+}
+
+static void wdm_wwan_port_tx_complete(struct urb *urb)
+{
+ struct sk_buff *skb = urb->context;
+ struct wdm_device *desc = skb_shinfo(skb)->destructor_arg;
+
+ usb_autopm_put_interface(desc->intf);
+ wwan_port_txon(desc->wwanp);
+ kfree_skb(skb);
+}
+
+static int wdm_wwan_port_tx(struct wwan_port *port, struct sk_buff *skb)
+{
+ struct wdm_device *desc = wwan_port_get_drvdata(port);
+ struct usb_interface *intf = desc->intf;
+ struct usb_ctrlrequest *req = desc->orq;
+ int rv;
+
+ rv = usb_autopm_get_interface(intf);
+ if (rv)
+ return rv;
+
+ usb_fill_control_urb(
+ desc->command,
+ interface_to_usbdev(intf),
+ usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+ (unsigned char *)req,
+ skb->data,
+ skb->len,
+ wdm_wwan_port_tx_complete,
+ skb
+ );
+
+ req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+ req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
+ req->wValue = 0;
+ req->wIndex = desc->inum;
+ req->wLength = cpu_to_le16(skb->len);
+
+ skb_shinfo(skb)->destructor_arg = desc;
+
+ rv = usb_submit_urb(desc->command, GFP_KERNEL);
+ if (rv)
+ usb_autopm_put_interface(intf);
+ else /* One transfer at a time, stop TX until URB completion */
+ wwan_port_txoff(port);
+
+ return rv;
+}
+
+static struct wwan_port_ops wdm_wwan_port_ops = {
+ .start = wdm_wwan_port_start,
+ .stop = wdm_wwan_port_stop,
+ .tx = wdm_wwan_port_tx,
+};
+
+static void wdm_wwan_init(struct wdm_device *desc)
+{
+ struct usb_interface *intf = desc->intf;
+ struct wwan_port *port;
+
+ /* Only register to WWAN core if protocol/type is known */
+ if (desc->wwanp_type == WWAN_PORT_UNKNOWN) {
+ dev_info(&intf->dev, "Unknown control protocol\n");
+ return;
+ }
+
+ port = wwan_create_port(&intf->dev, desc->wwanp_type, &wdm_wwan_port_ops, desc);
+ if (IS_ERR(port)) {
+ dev_err(&intf->dev, "%s: Unable to create WWAN port\n",
+ dev_name(intf->usb_dev));
+ return;
+ }
+
+ desc->wwanp = port;
+}
+
+static void wdm_wwan_deinit(struct wdm_device *desc)
+{
+ if (!desc->wwanp)
+ return;
+
+ wwan_remove_port(desc->wwanp);
+ desc->wwanp = NULL;
+}
+
+static void wdm_wwan_rx(struct wdm_device *desc, int length)
+{
+ struct wwan_port *port = desc->wwanp;
+ struct sk_buff *skb;
+
+ /* Forward data to WWAN port */
+ skb = alloc_skb(length, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ memcpy(skb_put(skb, length), desc->inbuf, length);
+ wwan_port_rx(port, skb);
+
+ /* inbuf has been copied, it is safe to check for outstanding data */
+ schedule_work(&desc->service_outs_intr);
+}
+#else /* CONFIG_WWAN */
+static void wdm_wwan_init(struct wdm_device *desc) {}
+static void wdm_wwan_deinit(struct wdm_device *desc) {}
+static void wdm_wwan_rx(struct wdm_device *desc, int length) {}
+#endif /* CONFIG_WWAN */
+
/* --- error handling --- */
static void wdm_rxwork(struct work_struct *work)
{
@@ -836,7 +1000,8 @@ static void service_interrupt_work(struct work_struct *work)
/* --- hotplug --- */
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
- u16 bufsize, int (*manage_power)(struct usb_interface *, int))
+ u16 bufsize, enum wwan_port_type type,
+ int (*manage_power)(struct usb_interface *, int))
{
int rv = -ENOMEM;
struct wdm_device *desc;
@@ -853,6 +1018,7 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
/* this will be expanded and needed in hardware endianness */
desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
desc->intf = intf;
+ desc->wwanp_type = type;
INIT_WORK(&desc->rxwork, wdm_rxwork);
INIT_WORK(&desc->service_outs_intr, service_interrupt_work);
@@ -933,6 +1099,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
goto err;
else
dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
+
+ wdm_wwan_init(desc);
+
out:
return rv;
err:
@@ -977,7 +1146,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto err;
ep = &iface->endpoint[0].desc;
- rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
+ rv = wdm_create(intf, ep, maxcom, WWAN_PORT_UNKNOWN, &wdm_manage_power);
err:
return rv;
@@ -988,6 +1157,7 @@ err:
* @intf: usb interface the subdriver will associate with
* @ep: interrupt endpoint to monitor for notifications
* @bufsize: maximum message size to support for read/write
+ * @type: Type/protocol of the transported data (MBIM, QMI...)
* @manage_power: call-back invoked during open and release to
* manage the device's power
* Create WDM usb class character device and associate it with intf
@@ -1005,12 +1175,12 @@ err:
*/
struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep,
- int bufsize,
+ int bufsize, enum wwan_port_type type,
int (*manage_power)(struct usb_interface *, int))
{
int rv;
- rv = wdm_create(intf, ep, bufsize, manage_power);
+ rv = wdm_create(intf, ep, bufsize, type, manage_power);
if (rv < 0)
goto err;
@@ -1029,6 +1199,8 @@ static void wdm_disconnect(struct usb_interface *intf)
desc = wdm_find_device(intf);
mutex_lock(&wdm_mutex);
+ wdm_wwan_deinit(desc);
+
/* the spinlock makes sure no new urbs are generated in the callbacks */
spin_lock_irqsave(&desc->iuspin, flags);
set_bit(WDM_DISCONNECTING, &desc->flags);
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index df82b124170e..6414bd5741b8 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -744,11 +744,9 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq,
if (copied != len)
return -EFAULT;
- xdp->data_hard_start = buf;
- xdp->data = buf + pad;
- xdp->data_end = xdp->data + len;
+ xdp_init_buff(xdp, buflen, NULL);
+ xdp_prepare_buff(xdp, buf, pad, len, true);
hdr->buflen = buflen;
- xdp->frame_sz = buflen;
--net->refcnt_bias;
alloc_frag->offset += buflen;
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 2cc35038a8ca..12e9a32dbca0 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -67,6 +67,7 @@ int br_multicast_list_adjacent(struct net_device *dev,
struct list_head *br_ip_list);
bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto);
bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto);
+bool br_multicast_has_router_adjacent(struct net_device *dev, int proto);
bool br_multicast_enabled(const struct net_device *dev);
bool br_multicast_router(const struct net_device *dev);
int br_mdb_replay(struct net_device *br_dev, struct net_device *dev,
@@ -87,6 +88,13 @@ static inline bool br_multicast_has_querier_adjacent(struct net_device *dev,
{
return false;
}
+
+static inline bool br_multicast_has_router_adjacent(struct net_device *dev,
+ int proto)
+{
+ return true;
+}
+
static inline bool br_multicast_enabled(const struct net_device *dev)
{
return false;
diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h
index 2b05e7f7c238..da633d34ab86 100644
--- a/include/linux/of_mdio.h
+++ b/include/linux/of_mdio.h
@@ -72,6 +72,13 @@ static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node *
return mdiobus_register(mdio);
}
+static inline int devm_of_mdiobus_register(struct device *dev,
+ struct mii_bus *mdio,
+ struct device_node *np)
+{
+ return devm_mdiobus_register(dev, mdio);
+}
+
static inline struct mdio_device *of_mdio_find_device(struct device_node *np)
{
return NULL;
diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
index 2cb5188a7ef1..5938ced805f4 100644
--- a/include/linux/pcs/pcs-xpcs.h
+++ b/include/linux/pcs/pcs-xpcs.h
@@ -32,6 +32,8 @@ struct mdio_xpcs_ops {
int (*link_up)(struct mdio_xpcs_args *xpcs, int speed,
phy_interface_t interface);
int (*probe)(struct mdio_xpcs_args *xpcs, phy_interface_t interface);
+ int (*config_eee)(struct mdio_xpcs_args *xpcs, int mult_fact_100ns,
+ int enable);
};
#if IS_ENABLED(CONFIG_PCS_XPCS)
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
index 0d47fd33b228..a311bddd9e85 100644
--- a/include/linux/ptp_clock_kernel.h
+++ b/include/linux/ptp_clock_kernel.h
@@ -186,6 +186,32 @@ struct ptp_clock_event {
};
};
+/**
+ * scaled_ppm_to_ppb() - convert scaled ppm to ppb
+ *
+ * @ppm: Parts per million, but with a 16 bit binary fractional field
+ */
+static inline s32 scaled_ppm_to_ppb(long ppm)
+{
+ /*
+ * The 'freq' field in the 'struct timex' is in parts per
+ * million, but with a 16 bit binary fractional field.
+ *
+ * We want to calculate
+ *
+ * ppb = scaled_ppm * 1000 / 2^16
+ *
+ * which simplifies to
+ *
+ * ppb = scaled_ppm * 125 / 2^13
+ */
+ s64 ppb = 1 + ppm;
+
+ ppb *= 125;
+ ppb >>= 13;
+ return (s32)ppb;
+}
+
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
/**
@@ -230,14 +256,6 @@ extern void ptp_clock_event(struct ptp_clock *ptp,
extern int ptp_clock_index(struct ptp_clock *ptp);
/**
- * scaled_ppm_to_ppb() - convert scaled ppm to ppb
- *
- * @ppm: Parts per million, but with a 16 bit binary fractional field
- */
-
-extern s32 scaled_ppm_to_ppb(long ppm);
-
-/**
* ptp_find_pin() - obtain the pin index of a given auxiliary function
*
* The caller must hold ptp_clock::pincfg_mux. Drivers do not have
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 0db36360ef21..e14a12df381b 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -223,6 +223,7 @@ struct plat_stmmacenet_data {
struct clk *clk_ptp_ref;
unsigned int clk_ptp_rate;
unsigned int clk_ref_rate;
+ unsigned int mult_fact_100ns;
s32 ptp_max_adj;
struct reset_control *stmmac_rst;
struct stmmac_axi *axi;
diff --git a/include/linux/usb/cdc-wdm.h b/include/linux/usb/cdc-wdm.h
index 9b895f93d8de..9f5a51f79ba5 100644
--- a/include/linux/usb/cdc-wdm.h
+++ b/include/linux/usb/cdc-wdm.h
@@ -12,11 +12,12 @@
#ifndef __LINUX_USB_CDC_WDM_H
#define __LINUX_USB_CDC_WDM_H
+#include <linux/wwan.h>
#include <uapi/linux/usb/cdc-wdm.h>
extern struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep,
- int bufsize,
+ int bufsize, enum wwan_port_type type,
int (*manage_power)(struct usb_interface *, int));
#endif /* __LINUX_USB_CDC_WDM_H */
diff --git a/include/linux/wwan.h b/include/linux/wwan.h
index aa05a253dcf9..7216c114d758 100644
--- a/include/linux/wwan.h
+++ b/include/linux/wwan.h
@@ -15,6 +15,7 @@
* @WWAN_PORT_QMI: Qcom modem/MSM interface for modem control
* @WWAN_PORT_QCDM: Qcom Modem diagnostic interface
* @WWAN_PORT_FIREHOSE: XML based command protocol
+ * @WWAN_PORT_UNKNOWN: Unknown port type
* @WWAN_PORT_MAX: Number of supported port types
*/
enum wwan_port_type {
@@ -23,7 +24,8 @@ enum wwan_port_type {
WWAN_PORT_QMI,
WWAN_PORT_QCDM,
WWAN_PORT_FIREHOSE,
- WWAN_PORT_MAX,
+ WWAN_PORT_UNKNOWN,
+ WWAN_PORT_MAX = WWAN_PORT_UNKNOWN,
};
struct wwan_port;
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index a914f33f3ed5..3ab2563b1a23 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -466,6 +466,49 @@ int fib_sync_up(struct net_device *dev, unsigned char nh_flags);
void fib_sync_mtu(struct net_device *dev, u32 orig_mtu);
void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig);
+/* Fields used for sysctl_fib_multipath_hash_fields.
+ * Common to IPv4 and IPv6.
+ *
+ * Add new fields at the end. This is user API.
+ */
+#define FIB_MULTIPATH_HASH_FIELD_SRC_IP BIT(0)
+#define FIB_MULTIPATH_HASH_FIELD_DST_IP BIT(1)
+#define FIB_MULTIPATH_HASH_FIELD_IP_PROTO BIT(2)
+#define FIB_MULTIPATH_HASH_FIELD_FLOWLABEL BIT(3)
+#define FIB_MULTIPATH_HASH_FIELD_SRC_PORT BIT(4)
+#define FIB_MULTIPATH_HASH_FIELD_DST_PORT BIT(5)
+#define FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP BIT(6)
+#define FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP BIT(7)
+#define FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO BIT(8)
+#define FIB_MULTIPATH_HASH_FIELD_INNER_FLOWLABEL BIT(9)
+#define FIB_MULTIPATH_HASH_FIELD_INNER_SRC_PORT BIT(10)
+#define FIB_MULTIPATH_HASH_FIELD_INNER_DST_PORT BIT(11)
+
+#define FIB_MULTIPATH_HASH_FIELD_OUTER_MASK \
+ (FIB_MULTIPATH_HASH_FIELD_SRC_IP | \
+ FIB_MULTIPATH_HASH_FIELD_DST_IP | \
+ FIB_MULTIPATH_HASH_FIELD_IP_PROTO | \
+ FIB_MULTIPATH_HASH_FIELD_FLOWLABEL | \
+ FIB_MULTIPATH_HASH_FIELD_SRC_PORT | \
+ FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+
+#define FIB_MULTIPATH_HASH_FIELD_INNER_MASK \
+ (FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP | \
+ FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP | \
+ FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO | \
+ FIB_MULTIPATH_HASH_FIELD_INNER_FLOWLABEL | \
+ FIB_MULTIPATH_HASH_FIELD_INNER_SRC_PORT | \
+ FIB_MULTIPATH_HASH_FIELD_INNER_DST_PORT)
+
+#define FIB_MULTIPATH_HASH_FIELD_ALL_MASK \
+ (FIB_MULTIPATH_HASH_FIELD_OUTER_MASK | \
+ FIB_MULTIPATH_HASH_FIELD_INNER_MASK)
+
+#define FIB_MULTIPATH_HASH_FIELD_DEFAULT_MASK \
+ (FIB_MULTIPATH_HASH_FIELD_SRC_IP | \
+ FIB_MULTIPATH_HASH_FIELD_DST_IP | \
+ FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+
#ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
const struct sk_buff *skb, struct flow_keys *flkeys);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 448bf2b34759..f2d0ecc257bb 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -926,11 +926,19 @@ static inline int ip6_multipath_hash_policy(const struct net *net)
{
return net->ipv6.sysctl.multipath_hash_policy;
}
+static inline u32 ip6_multipath_hash_fields(const struct net *net)
+{
+ return net->ipv6.sysctl.multipath_hash_fields;
+}
#else
static inline int ip6_multipath_hash_policy(const struct net *net)
{
return 0;
}
+static inline u32 ip6_multipath_hash_fields(const struct net *net)
+{
+ return 0;
+}
#endif
/*
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index f6af8d96d3c6..746c80cd4257 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -210,6 +210,7 @@ struct netns_ipv4 {
#endif
#endif
#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ u32 sysctl_fib_multipath_hash_fields;
u8 sysctl_fib_multipath_use_neigh;
u8 sysctl_fib_multipath_hash_policy;
#endif
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 6153c8067009..bde0b7adb4a3 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -28,8 +28,9 @@ struct netns_sysctl_ipv6 {
int ip6_rt_gc_elasticity;
int ip6_rt_mtu_expires;
int ip6_rt_min_advmss;
- u8 bindv6only;
+ u32 multipath_hash_fields;
u8 multipath_hash_policy;
+ u8 bindv6only;
u8 flowlabel_consistency;
u8 auto_flowlabels;
int icmpv6_time;
diff --git a/include/net/protocol.h b/include/net/protocol.h
index 2b778e1d2d8f..f51c06ae365f 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -43,7 +43,6 @@ struct net_protocol {
int (*err_handler)(struct sk_buff *skb, u32 info);
unsigned int no_policy:1,
- netns_ok:1,
/* does the protocol do more stringent
* icmp tag validation than simple
* socket lookup?
diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h
index ba94857eea11..521059d8dc0a 100644
--- a/include/trace/events/tcp.h
+++ b/include/trace/events/tcp.h
@@ -295,6 +295,82 @@ TRACE_EVENT(tcp_probe,
__entry->srtt, __entry->rcv_wnd, __entry->sock_cookie)
);
+#define TP_STORE_ADDR_PORTS_SKB_V4(__entry, skb) \
+ do { \
+ const struct tcphdr *th = (const struct tcphdr *)skb->data; \
+ struct sockaddr_in *v4 = (void *)__entry->saddr; \
+ \
+ v4->sin_family = AF_INET; \
+ v4->sin_port = th->source; \
+ v4->sin_addr.s_addr = ip_hdr(skb)->saddr; \
+ v4 = (void *)__entry->daddr; \
+ v4->sin_family = AF_INET; \
+ v4->sin_port = th->dest; \
+ v4->sin_addr.s_addr = ip_hdr(skb)->daddr; \
+ } while (0)
+
+#if IS_ENABLED(CONFIG_IPV6)
+
+#define TP_STORE_ADDR_PORTS_SKB(__entry, skb) \
+ do { \
+ const struct iphdr *iph = ip_hdr(skb); \
+ \
+ if (iph->version == 6) { \
+ const struct tcphdr *th = (const struct tcphdr *)skb->data; \
+ struct sockaddr_in6 *v6 = (void *)__entry->saddr; \
+ \
+ v6->sin6_family = AF_INET6; \
+ v6->sin6_port = th->source; \
+ v6->sin6_addr = ipv6_hdr(skb)->saddr; \
+ v6 = (void *)__entry->daddr; \
+ v6->sin6_family = AF_INET6; \
+ v6->sin6_port = th->dest; \
+ v6->sin6_addr = ipv6_hdr(skb)->daddr; \
+ } else \
+ TP_STORE_ADDR_PORTS_SKB_V4(__entry, skb); \
+ } while (0)
+
+#else
+
+#define TP_STORE_ADDR_PORTS_SKB(__entry, skb) \
+ TP_STORE_ADDR_PORTS_SKB_V4(__entry, skb)
+
+#endif
+
+/*
+ * tcp event with only skb
+ */
+DECLARE_EVENT_CLASS(tcp_event_skb,
+
+ TP_PROTO(const struct sk_buff *skb),
+
+ TP_ARGS(skb),
+
+ TP_STRUCT__entry(
+ __field(const void *, skbaddr)
+ __array(__u8, saddr, sizeof(struct sockaddr_in6))
+ __array(__u8, daddr, sizeof(struct sockaddr_in6))
+ ),
+
+ TP_fast_assign(
+ __entry->skbaddr = skb;
+
+ memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
+ memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
+
+ TP_STORE_ADDR_PORTS_SKB(__entry, skb);
+ ),
+
+ TP_printk("src=%pISpc dest=%pISpc", __entry->saddr, __entry->daddr)
+);
+
+DEFINE_EVENT(tcp_event_skb, tcp_bad_csum,
+
+ TP_PROTO(const struct sk_buff *skb),
+
+ TP_ARGS(skb)
+);
+
#endif /* _TRACE_TCP_H */
/* This part must be outside protection */
diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index 13d59c51ef5b..6b56a7549531 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -627,6 +627,8 @@ enum {
MDBA_ROUTER_PATTR_UNSPEC,
MDBA_ROUTER_PATTR_TIMER,
MDBA_ROUTER_PATTR_TYPE,
+ MDBA_ROUTER_PATTR_INET_TIMER,
+ MDBA_ROUTER_PATTR_INET6_TIMER,
__MDBA_ROUTER_PATTR_MAX
};
#define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 6e9b049ae521..07856362538f 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -276,7 +276,8 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
bool allow_mode_include = true;
struct hlist_node *rp;
- rp = rcu_dereference(hlist_first_rcu(&br->router_list));
+ rp = br_multicast_get_first_rport_node(br, skb);
+
if (mdst) {
p = rcu_dereference(mdst->ports);
if (br_multicast_should_handle_mode(br, mdst->addr.proto) &&
@@ -290,7 +291,7 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct net_bridge_port *port, *lport, *rport;
lport = p ? p->key.port : NULL;
- rport = hlist_entry_safe(rp, struct net_bridge_port, rlist);
+ rport = br_multicast_rport_from_node_skb(rp, skb);
if ((unsigned long)lport > (unsigned long)rport) {
port = lport;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 8875e953ac53..1f506309efa8 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -132,7 +132,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(br, eth_hdr(skb), mdst)) {
if ((mdst && mdst->host_joined) ||
- br_multicast_is_router(br)) {
+ br_multicast_is_router(br, skb)) {
local_rcv = true;
br->dev->stats.multicast++;
}
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 95fa4af0e8dd..3f839a8cc9fb 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -16,31 +16,76 @@
#include "br_private.h"
+static bool br_rports_have_mc_router(struct net_bridge *br)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ return !hlist_empty(&br->ip4_mc_router_list) ||
+ !hlist_empty(&br->ip6_mc_router_list);
+#else
+ return !hlist_empty(&br->ip4_mc_router_list);
+#endif
+}
+
+static bool
+br_ip4_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
+{
+ *timer = br_timer_value(&port->ip4_mc_router_timer);
+ return !hlist_unhashed(&port->ip4_rlist);
+}
+
+static bool
+br_ip6_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ *timer = br_timer_value(&port->ip6_mc_router_timer);
+ return !hlist_unhashed(&port->ip6_rlist);
+#else
+ *timer = 0;
+ return false;
+#endif
+}
+
static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
- struct net_bridge_port *p;
+ bool have_ip4_mc_rtr, have_ip6_mc_rtr;
+ unsigned long ip4_timer, ip6_timer;
struct nlattr *nest, *port_nest;
+ struct net_bridge_port *p;
- if (!br->multicast_router || hlist_empty(&br->router_list))
+ if (!br->multicast_router)
+ return 0;
+
+ if (!br_rports_have_mc_router(br))
return 0;
nest = nla_nest_start_noflag(skb, MDBA_ROUTER);
if (nest == NULL)
return -EMSGSIZE;
- hlist_for_each_entry_rcu(p, &br->router_list, rlist) {
- if (!p)
+ list_for_each_entry_rcu(p, &br->port_list, list) {
+ have_ip4_mc_rtr = br_ip4_rports_get_timer(p, &ip4_timer);
+ have_ip6_mc_rtr = br_ip6_rports_get_timer(p, &ip6_timer);
+
+ if (!have_ip4_mc_rtr && !have_ip6_mc_rtr)
continue;
+
port_nest = nla_nest_start_noflag(skb, MDBA_ROUTER_PORT);
if (!port_nest)
goto fail;
+
if (nla_put_nohdr(skb, sizeof(u32), &p->dev->ifindex) ||
nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER,
- br_timer_value(&p->multicast_router_timer)) ||
+ max(ip4_timer, ip6_timer)) ||
nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE,
- p->multicast_router)) {
+ p->multicast_router) ||
+ (have_ip4_mc_rtr &&
+ nla_put_u32(skb, MDBA_ROUTER_PATTR_INET_TIMER,
+ ip4_timer)) ||
+ (have_ip6_mc_rtr &&
+ nla_put_u32(skb, MDBA_ROUTER_PATTR_INET6_TIMER,
+ ip6_timer))) {
nla_nest_cancel(skb, port_nest);
goto fail;
}
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 226bb05c3b42..53c3a9d80d9c 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -51,8 +51,8 @@ static const struct rhashtable_params br_sg_port_rht_params = {
static void br_multicast_start_querier(struct net_bridge *br,
struct bridge_mcast_own_query *query);
-static void br_multicast_add_router(struct net_bridge *br,
- struct net_bridge_port *port);
+static void br_ip4_multicast_add_router(struct net_bridge *br,
+ struct net_bridge_port *port);
static void br_ip4_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port,
__be32 group,
@@ -60,7 +60,10 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
const unsigned char *src);
static void br_multicast_port_group_rexmit(struct timer_list *t);
-static void __del_port_router(struct net_bridge_port *p);
+static void
+br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted);
+static void br_ip6_multicast_add_router(struct net_bridge *br,
+ struct net_bridge_port *port);
#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port,
@@ -1354,23 +1357,64 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
}
#endif
-static void br_multicast_router_expired(struct timer_list *t)
+static bool br_multicast_rport_del(struct hlist_node *rlist)
+{
+ if (hlist_unhashed(rlist))
+ return false;
+
+ hlist_del_init_rcu(rlist);
+ return true;
+}
+
+static bool br_ip4_multicast_rport_del(struct net_bridge_port *p)
+{
+ return br_multicast_rport_del(&p->ip4_rlist);
+}
+
+static bool br_ip6_multicast_rport_del(struct net_bridge_port *p)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ return br_multicast_rport_del(&p->ip6_rlist);
+#else
+ return false;
+#endif
+}
+
+static void br_multicast_router_expired(struct net_bridge_port *port,
+ struct timer_list *t,
+ struct hlist_node *rlist)
{
- struct net_bridge_port *port =
- from_timer(port, t, multicast_router_timer);
struct net_bridge *br = port->br;
+ bool del;
spin_lock(&br->multicast_lock);
if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
port->multicast_router == MDB_RTR_TYPE_PERM ||
- timer_pending(&port->multicast_router_timer))
+ timer_pending(t))
goto out;
- __del_port_router(port);
+ del = br_multicast_rport_del(rlist);
+ br_multicast_rport_del_notify(port, del);
out:
spin_unlock(&br->multicast_lock);
}
+static void br_ip4_multicast_router_expired(struct timer_list *t)
+{
+ struct net_bridge_port *port = from_timer(port, t, ip4_mc_router_timer);
+
+ br_multicast_router_expired(port, t, &port->ip4_rlist);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_router_expired(struct timer_list *t)
+{
+ struct net_bridge_port *port = from_timer(port, t, ip6_mc_router_timer);
+
+ br_multicast_router_expired(port, t, &port->ip6_rlist);
+}
+#endif
+
static void br_mc_router_state_change(struct net_bridge *p,
bool is_mc_router)
{
@@ -1384,14 +1428,14 @@ static void br_mc_router_state_change(struct net_bridge *p,
switchdev_port_attr_set(p->dev, &attr, NULL);
}
-static void br_multicast_local_router_expired(struct timer_list *t)
+static void br_multicast_local_router_expired(struct net_bridge *br,
+ struct timer_list *timer)
{
- struct net_bridge *br = from_timer(br, t, multicast_router_timer);
-
spin_lock(&br->multicast_lock);
if (br->multicast_router == MDB_RTR_TYPE_DISABLED ||
br->multicast_router == MDB_RTR_TYPE_PERM ||
- timer_pending(&br->multicast_router_timer))
+ br_ip4_multicast_is_router(br) ||
+ br_ip6_multicast_is_router(br))
goto out;
br_mc_router_state_change(br, false);
@@ -1399,6 +1443,22 @@ out:
spin_unlock(&br->multicast_lock);
}
+static void br_ip4_multicast_local_router_expired(struct timer_list *t)
+{
+ struct net_bridge *br = from_timer(br, t, ip4_mc_router_timer);
+
+ br_multicast_local_router_expired(br, t);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_local_router_expired(struct timer_list *t)
+{
+ struct net_bridge *br = from_timer(br, t, ip6_mc_router_timer);
+
+ br_multicast_local_router_expired(br, t);
+}
+#endif
+
static void br_multicast_querier_expired(struct net_bridge *br,
struct bridge_mcast_own_query *query)
{
@@ -1613,11 +1673,13 @@ int br_multicast_add_port(struct net_bridge_port *port)
port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
port->multicast_eht_hosts_limit = BR_MCAST_DEFAULT_EHT_HOSTS_LIMIT;
- timer_setup(&port->multicast_router_timer,
- br_multicast_router_expired, 0);
+ timer_setup(&port->ip4_mc_router_timer,
+ br_ip4_multicast_router_expired, 0);
timer_setup(&port->ip4_own_query.timer,
br_ip4_multicast_port_query_expired, 0);
#if IS_ENABLED(CONFIG_IPV6)
+ timer_setup(&port->ip6_mc_router_timer,
+ br_ip6_multicast_router_expired, 0);
timer_setup(&port->ip6_own_query.timer,
br_ip6_multicast_port_query_expired, 0);
#endif
@@ -1649,7 +1711,10 @@ void br_multicast_del_port(struct net_bridge_port *port)
hlist_move_list(&br->mcast_gc_list, &deleted_head);
spin_unlock_bh(&br->multicast_lock);
br_multicast_gc(&deleted_head);
- del_timer_sync(&port->multicast_router_timer);
+ del_timer_sync(&port->ip4_mc_router_timer);
+#if IS_ENABLED(CONFIG_IPV6)
+ del_timer_sync(&port->ip6_mc_router_timer);
+#endif
free_percpu(port->mcast_stats);
}
@@ -1673,9 +1738,10 @@ static void __br_multicast_enable_port(struct net_bridge_port *port)
#if IS_ENABLED(CONFIG_IPV6)
br_multicast_enable(&port->ip6_own_query);
#endif
- if (port->multicast_router == MDB_RTR_TYPE_PERM &&
- hlist_unhashed(&port->rlist))
- br_multicast_add_router(br, port);
+ if (port->multicast_router == MDB_RTR_TYPE_PERM) {
+ br_ip4_multicast_add_router(br, port);
+ br_ip6_multicast_add_router(br, port);
+ }
}
void br_multicast_enable_port(struct net_bridge_port *port)
@@ -1692,19 +1758,22 @@ void br_multicast_disable_port(struct net_bridge_port *port)
struct net_bridge *br = port->br;
struct net_bridge_port_group *pg;
struct hlist_node *n;
+ bool del = false;
spin_lock(&br->multicast_lock);
hlist_for_each_entry_safe(pg, n, &port->mglist, mglist)
if (!(pg->flags & MDB_PG_FLAGS_PERMANENT))
br_multicast_find_del_pg(br, pg);
- __del_port_router(port);
-
- del_timer(&port->multicast_router_timer);
+ del |= br_ip4_multicast_rport_del(port);
+ del_timer(&port->ip4_mc_router_timer);
del_timer(&port->ip4_own_query.timer);
+ del |= br_ip6_multicast_rport_del(port);
#if IS_ENABLED(CONFIG_IPV6)
+ del_timer(&port->ip6_mc_router_timer);
del_timer(&port->ip6_own_query.timer);
#endif
+ br_multicast_rport_del_notify(port, del);
spin_unlock(&br->multicast_lock);
}
@@ -2615,22 +2684,6 @@ update:
}
#endif
-static bool br_multicast_select_querier(struct net_bridge *br,
- struct net_bridge_port *port,
- struct br_ip *saddr)
-{
- switch (saddr->proto) {
- case htons(ETH_P_IP):
- return br_ip4_multicast_select_querier(br, port, saddr->src.ip4);
-#if IS_ENABLED(CONFIG_IPV6)
- case htons(ETH_P_IPV6):
- return br_ip6_multicast_select_querier(br, port, &saddr->src.ip6);
-#endif
- }
-
- return false;
-}
-
static void
br_multicast_update_query_timer(struct net_bridge *br,
struct bridge_mcast_other_query *query,
@@ -2655,45 +2708,122 @@ static void br_port_mc_router_state_change(struct net_bridge_port *p,
switchdev_port_attr_set(p->dev, &attr, NULL);
}
-/*
- * Add port to router_list
+static struct net_bridge_port *
+br_multicast_rport_from_node(struct net_bridge *br,
+ struct hlist_head *mc_router_list,
+ struct hlist_node *rlist)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ if (mc_router_list == &br->ip6_mc_router_list)
+ return hlist_entry(rlist, struct net_bridge_port, ip6_rlist);
+#endif
+ return hlist_entry(rlist, struct net_bridge_port, ip4_rlist);
+}
+
+static struct hlist_node *
+br_multicast_get_rport_slot(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct hlist_head *mc_router_list)
+
+{
+ struct hlist_node *slot = NULL;
+ struct net_bridge_port *p;
+ struct hlist_node *rlist;
+
+ hlist_for_each(rlist, mc_router_list) {
+ p = br_multicast_rport_from_node(br, mc_router_list, rlist);
+
+ if ((unsigned long)port >= (unsigned long)p)
+ break;
+
+ slot = rlist;
+ }
+
+ return slot;
+}
+
+static bool br_multicast_no_router_otherpf(struct net_bridge_port *port,
+ struct hlist_node *rnode)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ if (rnode != &port->ip6_rlist)
+ return hlist_unhashed(&port->ip6_rlist);
+ else
+ return hlist_unhashed(&port->ip4_rlist);
+#else
+ return true;
+#endif
+}
+
+/* Add port to router_list
* list is maintained ordered by pointer value
* and locked by br->multicast_lock and RCU
*/
static void br_multicast_add_router(struct net_bridge *br,
- struct net_bridge_port *port)
+ struct net_bridge_port *port,
+ struct hlist_node *rlist,
+ struct hlist_head *mc_router_list)
{
- struct net_bridge_port *p;
- struct hlist_node *slot = NULL;
+ struct hlist_node *slot;
- if (!hlist_unhashed(&port->rlist))
+ if (!hlist_unhashed(rlist))
return;
- hlist_for_each_entry(p, &br->router_list, rlist) {
- if ((unsigned long) port >= (unsigned long) p)
- break;
- slot = &p->rlist;
- }
+ slot = br_multicast_get_rport_slot(br, port, mc_router_list);
if (slot)
- hlist_add_behind_rcu(&port->rlist, slot);
+ hlist_add_behind_rcu(rlist, slot);
else
- hlist_add_head_rcu(&port->rlist, &br->router_list);
- br_rtr_notify(br->dev, port, RTM_NEWMDB);
- br_port_mc_router_state_change(port, true);
+ hlist_add_head_rcu(rlist, mc_router_list);
+
+ /* For backwards compatibility for now, only notify if we
+ * switched from no IPv4/IPv6 multicast router to a new
+ * IPv4 or IPv6 multicast router.
+ */
+ if (br_multicast_no_router_otherpf(port, rlist)) {
+ br_rtr_notify(br->dev, port, RTM_NEWMDB);
+ br_port_mc_router_state_change(port, true);
+ }
+}
+
+/* Add port to router_list
+ * list is maintained ordered by pointer value
+ * and locked by br->multicast_lock and RCU
+ */
+static void br_ip4_multicast_add_router(struct net_bridge *br,
+ struct net_bridge_port *port)
+{
+ br_multicast_add_router(br, port, &port->ip4_rlist,
+ &br->ip4_mc_router_list);
+}
+
+/* Add port to router_list
+ * list is maintained ordered by pointer value
+ * and locked by br->multicast_lock and RCU
+ */
+static void br_ip6_multicast_add_router(struct net_bridge *br,
+ struct net_bridge_port *port)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ br_multicast_add_router(br, port, &port->ip6_rlist,
+ &br->ip6_mc_router_list);
+#endif
}
static void br_multicast_mark_router(struct net_bridge *br,
- struct net_bridge_port *port)
+ struct net_bridge_port *port,
+ struct timer_list *timer,
+ struct hlist_node *rlist,
+ struct hlist_head *mc_router_list)
{
unsigned long now = jiffies;
if (!port) {
if (br->multicast_router == MDB_RTR_TYPE_TEMP_QUERY) {
- if (!timer_pending(&br->multicast_router_timer))
+ if (!br_ip4_multicast_is_router(br) &&
+ !br_ip6_multicast_is_router(br))
br_mc_router_state_change(br, true);
- mod_timer(&br->multicast_router_timer,
- now + br->multicast_querier_interval);
+ mod_timer(timer, now + br->multicast_querier_interval);
}
return;
}
@@ -2702,24 +2832,71 @@ static void br_multicast_mark_router(struct net_bridge *br,
port->multicast_router == MDB_RTR_TYPE_PERM)
return;
- br_multicast_add_router(br, port);
+ br_multicast_add_router(br, port, rlist, mc_router_list);
+ mod_timer(timer, now + br->multicast_querier_interval);
+}
+
+static void br_ip4_multicast_mark_router(struct net_bridge *br,
+ struct net_bridge_port *port)
+{
+ struct timer_list *timer = &br->ip4_mc_router_timer;
+ struct hlist_node *rlist = NULL;
+
+ if (port) {
+ timer = &port->ip4_mc_router_timer;
+ rlist = &port->ip4_rlist;
+ }
- mod_timer(&port->multicast_router_timer,
- now + br->multicast_querier_interval);
+ br_multicast_mark_router(br, port, timer, rlist,
+ &br->ip4_mc_router_list);
}
-static void br_multicast_query_received(struct net_bridge *br,
- struct net_bridge_port *port,
- struct bridge_mcast_other_query *query,
- struct br_ip *saddr,
- unsigned long max_delay)
+static void br_ip6_multicast_mark_router(struct net_bridge *br,
+ struct net_bridge_port *port)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ struct timer_list *timer = &br->ip6_mc_router_timer;
+ struct hlist_node *rlist = NULL;
+
+ if (port) {
+ timer = &port->ip6_mc_router_timer;
+ rlist = &port->ip6_rlist;
+ }
+
+ br_multicast_mark_router(br, port, timer, rlist,
+ &br->ip6_mc_router_list);
+#endif
+}
+
+static void
+br_ip4_multicast_query_received(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct bridge_mcast_other_query *query,
+ struct br_ip *saddr,
+ unsigned long max_delay)
+{
+ if (!br_ip4_multicast_select_querier(br, port, saddr->src.ip4))
+ return;
+
+ br_multicast_update_query_timer(br, query, max_delay);
+ br_ip4_multicast_mark_router(br, port);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void
+br_ip6_multicast_query_received(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct bridge_mcast_other_query *query,
+ struct br_ip *saddr,
+ unsigned long max_delay)
{
- if (!br_multicast_select_querier(br, port, saddr))
+ if (!br_ip6_multicast_select_querier(br, port, &saddr->src.ip6))
return;
br_multicast_update_query_timer(br, query, max_delay);
- br_multicast_mark_router(br, port);
+ br_ip6_multicast_mark_router(br, port);
}
+#endif
static void br_ip4_multicast_query(struct net_bridge *br,
struct net_bridge_port *port,
@@ -2768,8 +2945,8 @@ static void br_ip4_multicast_query(struct net_bridge *br,
saddr.proto = htons(ETH_P_IP);
saddr.src.ip4 = iph->saddr;
- br_multicast_query_received(br, port, &br->ip4_other_query,
- &saddr, max_delay);
+ br_ip4_multicast_query_received(br, port, &br->ip4_other_query,
+ &saddr, max_delay);
goto out;
}
@@ -2856,8 +3033,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
saddr.proto = htons(ETH_P_IPV6);
saddr.src.ip6 = ipv6_hdr(skb)->saddr;
- br_multicast_query_received(br, port, &br->ip6_other_query,
- &saddr, max_delay);
+ br_ip6_multicast_query_received(br, port, &br->ip6_other_query,
+ &saddr, max_delay);
goto out;
} else if (!group) {
goto out;
@@ -3087,7 +3264,7 @@ static void br_multicast_pim(struct net_bridge *br,
pim_hdr_type(pimhdr) != PIM_TYPE_HELLO)
return;
- br_multicast_mark_router(br, port);
+ br_ip4_multicast_mark_router(br, port);
}
static int br_ip4_multicast_mrd_rcv(struct net_bridge *br,
@@ -3098,7 +3275,7 @@ static int br_ip4_multicast_mrd_rcv(struct net_bridge *br,
igmp_hdr(skb)->type != IGMP_MRDISC_ADV)
return -ENOMSG;
- br_multicast_mark_router(br, port);
+ br_ip4_multicast_mark_router(br, port);
return 0;
}
@@ -3166,7 +3343,7 @@ static void br_ip6_multicast_mrd_rcv(struct net_bridge *br,
if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV)
return;
- br_multicast_mark_router(br, port);
+ br_ip6_multicast_mark_router(br, port);
}
static int br_multicast_ipv6_rcv(struct net_bridge *br,
@@ -3316,13 +3493,15 @@ void br_multicast_init(struct net_bridge *br)
br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true);
spin_lock_init(&br->multicast_lock);
- timer_setup(&br->multicast_router_timer,
- br_multicast_local_router_expired, 0);
+ timer_setup(&br->ip4_mc_router_timer,
+ br_ip4_multicast_local_router_expired, 0);
timer_setup(&br->ip4_other_query.timer,
br_ip4_multicast_querier_expired, 0);
timer_setup(&br->ip4_own_query.timer,
br_ip4_multicast_query_expired, 0);
#if IS_ENABLED(CONFIG_IPV6)
+ timer_setup(&br->ip6_mc_router_timer,
+ br_ip6_multicast_local_router_expired, 0);
timer_setup(&br->ip6_other_query.timer,
br_ip6_multicast_querier_expired, 0);
timer_setup(&br->ip6_own_query.timer,
@@ -3416,10 +3595,11 @@ void br_multicast_open(struct net_bridge *br)
void br_multicast_stop(struct net_bridge *br)
{
- del_timer_sync(&br->multicast_router_timer);
+ del_timer_sync(&br->ip4_mc_router_timer);
del_timer_sync(&br->ip4_other_query.timer);
del_timer_sync(&br->ip4_own_query.timer);
#if IS_ENABLED(CONFIG_IPV6)
+ del_timer_sync(&br->ip6_mc_router_timer);
del_timer_sync(&br->ip6_other_query.timer);
del_timer_sync(&br->ip6_own_query.timer);
#endif
@@ -3453,7 +3633,10 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
case MDB_RTR_TYPE_DISABLED:
case MDB_RTR_TYPE_PERM:
br_mc_router_state_change(br, val == MDB_RTR_TYPE_PERM);
- del_timer(&br->multicast_router_timer);
+ del_timer(&br->ip4_mc_router_timer);
+#if IS_ENABLED(CONFIG_IPV6)
+ del_timer(&br->ip6_mc_router_timer);
+#endif
br->multicast_router = val;
err = 0;
break;
@@ -3470,11 +3653,22 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
return err;
}
-static void __del_port_router(struct net_bridge_port *p)
+static void
+br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted)
{
- if (hlist_unhashed(&p->rlist))
+ if (!deleted)
+ return;
+
+ /* For backwards compatibility for now, only notify if there is
+ * no multicast router anymore for both IPv4 and IPv6.
+ */
+ if (!hlist_unhashed(&p->ip4_rlist))
return;
- hlist_del_init_rcu(&p->rlist);
+#if IS_ENABLED(CONFIG_IPV6)
+ if (!hlist_unhashed(&p->ip6_rlist))
+ return;
+#endif
+
br_rtr_notify(p->br->dev, p, RTM_DELMDB);
br_port_mc_router_state_change(p, false);
@@ -3488,34 +3682,52 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
struct net_bridge *br = p->br;
unsigned long now = jiffies;
int err = -EINVAL;
+ bool del = false;
spin_lock(&br->multicast_lock);
if (p->multicast_router == val) {
/* Refresh the temp router port timer */
- if (p->multicast_router == MDB_RTR_TYPE_TEMP)
- mod_timer(&p->multicast_router_timer,
+ if (p->multicast_router == MDB_RTR_TYPE_TEMP) {
+ mod_timer(&p->ip4_mc_router_timer,
now + br->multicast_querier_interval);
+#if IS_ENABLED(CONFIG_IPV6)
+ mod_timer(&p->ip6_mc_router_timer,
+ now + br->multicast_querier_interval);
+#endif
+ }
err = 0;
goto unlock;
}
switch (val) {
case MDB_RTR_TYPE_DISABLED:
p->multicast_router = MDB_RTR_TYPE_DISABLED;
- __del_port_router(p);
- del_timer(&p->multicast_router_timer);
+ del |= br_ip4_multicast_rport_del(p);
+ del_timer(&p->ip4_mc_router_timer);
+ del |= br_ip6_multicast_rport_del(p);
+#if IS_ENABLED(CONFIG_IPV6)
+ del_timer(&p->ip6_mc_router_timer);
+#endif
+ br_multicast_rport_del_notify(p, del);
break;
case MDB_RTR_TYPE_TEMP_QUERY:
p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
- __del_port_router(p);
+ del |= br_ip4_multicast_rport_del(p);
+ del |= br_ip6_multicast_rport_del(p);
+ br_multicast_rport_del_notify(p, del);
break;
case MDB_RTR_TYPE_PERM:
p->multicast_router = MDB_RTR_TYPE_PERM;
- del_timer(&p->multicast_router_timer);
- br_multicast_add_router(br, p);
+ del_timer(&p->ip4_mc_router_timer);
+ br_ip4_multicast_add_router(br, p);
+#if IS_ENABLED(CONFIG_IPV6)
+ del_timer(&p->ip6_mc_router_timer);
+#endif
+ br_ip6_multicast_add_router(br, p);
break;
case MDB_RTR_TYPE_TEMP:
p->multicast_router = MDB_RTR_TYPE_TEMP;
- br_multicast_mark_router(br, p);
+ br_ip4_multicast_mark_router(br, p);
+ br_ip6_multicast_mark_router(br, p);
break;
default:
goto unlock;
@@ -3621,7 +3833,7 @@ bool br_multicast_router(const struct net_device *dev)
bool is_router;
spin_lock_bh(&br->multicast_lock);
- is_router = br_multicast_is_router(br);
+ is_router = br_multicast_is_router(br, NULL);
spin_unlock_bh(&br->multicast_lock);
return is_router;
}
@@ -3842,6 +4054,61 @@ unlock:
}
EXPORT_SYMBOL_GPL(br_multicast_has_querier_adjacent);
+/**
+ * br_multicast_has_router_adjacent - Checks for a router behind a bridge port
+ * @dev: The bridge port adjacent to which to check for a multicast router
+ * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6
+ *
+ * Checks whether the given interface has a bridge on top and if so returns
+ * true if a multicast router is behind one of the other ports of this
+ * bridge. Otherwise returns false.
+ */
+bool br_multicast_has_router_adjacent(struct net_device *dev, int proto)
+{
+ struct net_bridge_port *port, *p;
+ bool ret = false;
+
+ rcu_read_lock();
+ port = br_port_get_check_rcu(dev);
+ if (!port)
+ goto unlock;
+
+ switch (proto) {
+ case ETH_P_IP:
+ hlist_for_each_entry_rcu(p, &port->br->ip4_mc_router_list,
+ ip4_rlist) {
+ if (p == port)
+ continue;
+
+ ret = true;
+ goto unlock;
+ }
+ break;
+#if IS_ENABLED(CONFIG_IPV6)
+ case ETH_P_IPV6:
+ hlist_for_each_entry_rcu(p, &port->br->ip6_mc_router_list,
+ ip6_rlist) {
+ if (p == port)
+ continue;
+
+ ret = true;
+ goto unlock;
+ }
+ break;
+#endif
+ default:
+ /* when compiled without IPv6 support, be conservative and
+ * always assume presence of an IPv6 multicast router
+ */
+ ret = true;
+ }
+
+unlock:
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(br_multicast_has_router_adjacent);
+
static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats,
const struct sk_buff *skb, u8 type, u8 dir)
{
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 7ce8a77cc6b6..ec661130c2d0 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -307,16 +307,18 @@ struct net_bridge_port {
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
struct bridge_mcast_own_query ip4_own_query;
+ struct timer_list ip4_mc_router_timer;
+ struct hlist_node ip4_rlist;
#if IS_ENABLED(CONFIG_IPV6)
struct bridge_mcast_own_query ip6_own_query;
+ struct timer_list ip6_mc_router_timer;
+ struct hlist_node ip6_rlist;
#endif /* IS_ENABLED(CONFIG_IPV6) */
u32 multicast_eht_hosts_limit;
u32 multicast_eht_hosts_cnt;
unsigned char multicast_router;
struct bridge_mcast_stats __percpu *mcast_stats;
- struct timer_list multicast_router_timer;
struct hlist_head mglist;
- struct hlist_node rlist;
#endif
#ifdef CONFIG_SYSFS
@@ -449,14 +451,16 @@ struct net_bridge {
struct hlist_head mcast_gc_list;
struct hlist_head mdb_list;
- struct hlist_head router_list;
- struct timer_list multicast_router_timer;
+ struct hlist_head ip4_mc_router_list;
+ struct timer_list ip4_mc_router_timer;
struct bridge_mcast_other_query ip4_other_query;
struct bridge_mcast_own_query ip4_own_query;
struct bridge_mcast_querier ip4_querier;
struct bridge_mcast_stats __percpu *mcast_stats;
#if IS_ENABLED(CONFIG_IPV6)
+ struct hlist_head ip6_mc_router_list;
+ struct timer_list ip6_mc_router_timer;
struct bridge_mcast_other_query ip6_other_query;
struct bridge_mcast_own_query ip6_own_query;
struct bridge_mcast_querier ip6_querier;
@@ -864,11 +868,58 @@ static inline bool br_group_is_l2(const struct br_ip *group)
#define mlock_dereference(X, br) \
rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
-static inline bool br_multicast_is_router(struct net_bridge *br)
+static inline struct hlist_node *
+br_multicast_get_first_rport_node(struct net_bridge *b, struct sk_buff *skb) {
+#if IS_ENABLED(CONFIG_IPV6)
+ if (skb->protocol == htons(ETH_P_IPV6))
+ return rcu_dereference(hlist_first_rcu(&b->ip6_mc_router_list));
+#endif
+ return rcu_dereference(hlist_first_rcu(&b->ip4_mc_router_list));
+}
+
+static inline struct net_bridge_port *
+br_multicast_rport_from_node_skb(struct hlist_node *rp, struct sk_buff *skb) {
+#if IS_ENABLED(CONFIG_IPV6)
+ if (skb->protocol == htons(ETH_P_IPV6))
+ return hlist_entry_safe(rp, struct net_bridge_port, ip6_rlist);
+#endif
+ return hlist_entry_safe(rp, struct net_bridge_port, ip4_rlist);
+}
+
+static inline bool br_ip4_multicast_is_router(struct net_bridge *br)
+{
+ return timer_pending(&br->ip4_mc_router_timer);
+}
+
+static inline bool br_ip6_multicast_is_router(struct net_bridge *br)
{
- return br->multicast_router == 2 ||
- (br->multicast_router == 1 &&
- timer_pending(&br->multicast_router_timer));
+#if IS_ENABLED(CONFIG_IPV6)
+ return timer_pending(&br->ip6_mc_router_timer);
+#else
+ return false;
+#endif
+}
+
+static inline bool
+br_multicast_is_router(struct net_bridge *br, struct sk_buff *skb)
+{
+ switch (br->multicast_router) {
+ case MDB_RTR_TYPE_PERM:
+ return true;
+ case MDB_RTR_TYPE_TEMP_QUERY:
+ if (skb) {
+ if (skb->protocol == htons(ETH_P_IP))
+ return br_ip4_multicast_is_router(br);
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ return br_ip6_multicast_is_router(br);
+ } else {
+ return br_ip4_multicast_is_router(br) ||
+ br_ip6_multicast_is_router(br);
+ }
+ fallthrough;
+ default:
+ return false;
+ }
}
static inline bool
@@ -1017,7 +1068,8 @@ static inline void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
{
}
-static inline bool br_multicast_is_router(struct net_bridge *br)
+static inline bool br_multicast_is_router(struct net_bridge *br,
+ struct sk_buff *skb)
{
return false;
}
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index fadc7c8a3107..37b67194c0df 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -76,8 +76,6 @@ static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt)
u8 buf;
priv = container_of(layr, struct chnl_net, chnl);
- if (!priv)
- return -EINVAL;
skb = (struct sk_buff *) cfpkt_tonative(pkt);
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index cc3712ad8716..f564f82e91d9 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -524,8 +524,7 @@ bpf_sk_storage_diag_alloc(const struct nlattr *nla_stgs)
nr_maps++;
}
- diag = kzalloc(sizeof(*diag) + sizeof(diag->maps[0]) * nr_maps,
- GFP_KERNEL);
+ diag = kzalloc(struct_size(diag, maps, nr_maps), GFP_KERNEL);
if (!diag)
return ERR_PTR(-ENOMEM);
diff --git a/net/core/dev.c b/net/core/dev.c
index 222b1d322c96..febb23708184 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6501,11 +6501,18 @@ EXPORT_SYMBOL(napi_schedule_prep);
* __napi_schedule_irqoff - schedule for receive
* @n: entry to schedule
*
- * Variant of __napi_schedule() assuming hard irqs are masked
+ * Variant of __napi_schedule() assuming hard irqs are masked.
+ *
+ * On PREEMPT_RT enabled kernels this maps to __napi_schedule()
+ * because the interrupt disabled assumption might not be true
+ * due to force-threaded interrupts and spinlock substitution.
*/
void __napi_schedule_irqoff(struct napi_struct *n)
{
- ____napi_schedule(this_cpu_ptr(&softnet_data), n);
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
+ ____napi_schedule(this_cpu_ptr(&softnet_data), n);
+ else
+ __napi_schedule(n);
}
EXPORT_SYMBOL(__napi_schedule_irqoff);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 98f20efbfadf..2b2f333bcdfe 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -3141,7 +3141,7 @@ static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
struct net *net = seq_file_net(seq);
struct neigh_table *tbl = state->tbl;
struct pneigh_entry *pn = NULL;
- int bucket = state->bucket;
+ int bucket;
state->flags |= NEIGH_SEQ_IS_PNEIGH;
for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
diff --git a/net/core/net-traces.c b/net/core/net-traces.c
index 283ddb2dbc7d..c40cd8dd75c7 100644
--- a/net/core/net-traces.c
+++ b/net/core/net-traces.c
@@ -60,3 +60,4 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb);
EXPORT_TRACEPOINT_SYMBOL_GPL(napi_poll);
EXPORT_TRACEPOINT_SYMBOL_GPL(tcp_send_reset);
+EXPORT_TRACEPOINT_SYMBOL_GPL(tcp_bad_csum);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 714d5fa38546..04b4f0f2a3d2 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -543,7 +543,9 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family)
{
const struct rtnl_af_ops *ops;
- list_for_each_entry_rcu(ops, &rtnl_af_ops, list) {
+ ASSERT_RTNL();
+
+ list_for_each_entry(ops, &rtnl_af_ops, list) {
if (ops->family == family)
return ops;
}
@@ -2274,27 +2276,18 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
const struct rtnl_af_ops *af_ops;
- rcu_read_lock();
af_ops = rtnl_af_lookup(nla_type(af));
- if (!af_ops) {
- rcu_read_unlock();
+ if (!af_ops)
return -EAFNOSUPPORT;
- }
- if (!af_ops->set_link_af) {
- rcu_read_unlock();
+ if (!af_ops->set_link_af)
return -EOPNOTSUPP;
- }
if (af_ops->validate_link_af) {
err = af_ops->validate_link_af(dev, af);
- if (err < 0) {
- rcu_read_unlock();
+ if (err < 0)
return err;
- }
}
-
- rcu_read_unlock();
}
}
@@ -2868,17 +2861,12 @@ static int do_setlink(const struct sk_buff *skb,
nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
const struct rtnl_af_ops *af_ops;
- rcu_read_lock();
-
BUG_ON(!(af_ops = rtnl_af_lookup(nla_type(af))));
err = af_ops->set_link_af(dev, af, extack);
- if (err < 0) {
- rcu_read_unlock();
+ if (err < 0)
goto errout;
- }
- rcu_read_unlock();
status |= DO_SETLINK_NOTIFY;
}
}
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index 653e3bc9c87b..51f80a2f8194 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -2075,8 +2075,6 @@ EXPORT_SYMBOL(dcb_ieee_getapp_default_prio_mask);
static int __init dcbnl_init(void)
{
- INIT_LIST_HEAD(&dcb_app_list);
-
rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, 0);
rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, 0);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index ffc601a3b329..f81c1df761d3 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -977,7 +977,6 @@ static const struct net_protocol dccp_v4_protocol = {
.handler = dccp_v4_rcv,
.err_handler = dccp_v4_err,
.no_policy = 1,
- .netns_ok = 1,
.icmp_strict_tag_validation = 1,
};
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index f17870ee558b..d9bccad65e2b 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1720,7 +1720,6 @@ EXPORT_SYMBOL_GPL(snmp_fold_field64);
#ifdef CONFIG_IP_MULTICAST
static const struct net_protocol igmp_protocol = {
.handler = igmp_rcv,
- .netns_ok = 1,
};
#endif
@@ -1733,7 +1732,6 @@ static struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.no_policy = 1,
- .netns_ok = 1,
.icmp_strict_tag_validation = 1,
};
@@ -1746,14 +1744,12 @@ static struct net_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
.no_policy = 1,
- .netns_ok = 1,
};
static const struct net_protocol icmp_protocol = {
.handler = icmp_rcv,
.err_handler = icmp_err,
.no_policy = 1,
- .netns_ok = 1,
};
static __net_init int ipv4_mib_init_net(struct net *net)
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index bfaf327e9d12..d6e3a92841e3 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -187,8 +187,7 @@ static int __init cipso_v4_cache_init(void)
* cipso_v4_cache_invalidate - Invalidates the current CIPSO cache
*
* Description:
- * Invalidates and frees any entries in the CIPSO cache. Returns zero on
- * success and negative values on failure.
+ * Invalidates and frees any entries in the CIPSO cache.
*
*/
void cipso_v4_cache_invalidate(void)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 2e35f68da40a..50deeff48c8b 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1955,7 +1955,7 @@ static int inet_validate_link_af(const struct net_device *dev,
struct nlattr *a, *tb[IFLA_INET_MAX+1];
int err, rem;
- if (dev && !__in_dev_get_rcu(dev))
+ if (dev && !__in_dev_get_rtnl(dev))
return -EAFNOSUPPORT;
err = nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla,
@@ -1981,7 +1981,7 @@ static int inet_validate_link_af(const struct net_device *dev,
static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla,
struct netlink_ext_ack *extack)
{
- struct in_device *in_dev = __in_dev_get_rcu(dev);
+ struct in_device *in_dev = __in_dev_get_rtnl(dev);
struct nlattr *a, *tb[IFLA_INET_MAX+1];
int rem;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 84bb707bd88d..af8814a11378 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1122,10 +1122,8 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
prefix, ifa->ifa_prefixlen, prim,
ifa->ifa_rt_priority);
- /* Add network specific broadcasts, when it takes a sense */
+ /* Add the network broadcast address, when it makes sense */
if (ifa->ifa_prefixlen < 31) {
- fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32,
- prim, 0);
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
32, prim, 0);
}
@@ -1516,6 +1514,12 @@ static int __net_init ip_fib_net_init(struct net *net)
if (err)
return err;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ /* Default to 3-tuple */
+ net->ipv4.sysctl_fib_multipath_hash_fields =
+ FIB_MULTIPATH_HASH_FIELD_DEFAULT_MASK;
+#endif
+
/* Avoid false sharing : Use at least a full cache line */
size = max_t(size_t, size, L1_CACHE_BYTES);
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c
index 5d1e6fe9d838..cbb2b4bb0dfa 100644
--- a/net/ipv4/gre_demux.c
+++ b/net/ipv4/gre_demux.c
@@ -195,7 +195,6 @@ static int gre_err(struct sk_buff *skb, u32 info)
static const struct net_protocol net_gre_protocol = {
.handler = gre_rcv,
.err_handler = gre_err,
- .netns_ok = 1,
};
static int __init gre_init(void)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 939792a38814..12b564b1ecb4 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -3007,7 +3007,6 @@ static const struct seq_operations ipmr_mfc_seq_ops = {
#ifdef CONFIG_IP_PIMSM_V2
static const struct net_protocol pim_protocol = {
.handler = pim_rcv,
- .netns_ok = 1,
};
#endif
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index 9a8c0892622b..6913979948d7 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -31,12 +31,6 @@ EXPORT_SYMBOL(inet_offloads);
int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
{
- if (!prot->netns_ok) {
- pr_err("Protocol %u is not namespace aware, cannot register.\n",
- protocol);
- return -EINVAL;
- }
-
return !cmpxchg((const struct net_protocol **)&inet_protos[protocol],
NULL, prot) ? 0 : -1;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index f6787c55f6ab..a4c477475f4c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1906,13 +1906,128 @@ out:
hash_keys->addrs.v4addrs.dst = key_iph->daddr;
}
+static u32 fib_multipath_custom_hash_outer(const struct net *net,
+ const struct sk_buff *skb,
+ bool *p_has_inner)
+{
+ u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+ struct flow_keys keys, hash_keys;
+
+ if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_OUTER_MASK))
+ return 0;
+
+ memset(&hash_keys, 0, sizeof(hash_keys));
+ skb_flow_dissect_flow_keys(skb, &keys, FLOW_DISSECTOR_F_STOP_AT_ENCAP);
+
+ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP)
+ hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP)
+ hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+ hash_keys.basic.ip_proto = keys.basic.ip_proto;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
+ hash_keys.ports.src = keys.ports.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+ hash_keys.ports.dst = keys.ports.dst;
+
+ *p_has_inner = !!(keys.control.flags & FLOW_DIS_ENCAPSULATION);
+ return flow_hash_from_keys(&hash_keys);
+}
+
+static u32 fib_multipath_custom_hash_inner(const struct net *net,
+ const struct sk_buff *skb,
+ bool has_inner)
+{
+ u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+ struct flow_keys keys, hash_keys;
+
+ /* We assume the packet carries an encapsulation, but if none was
+ * encountered during dissection of the outer flow, then there is no
+ * point in calling the flow dissector again.
+ */
+ if (!has_inner)
+ return 0;
+
+ if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_MASK))
+ return 0;
+
+ memset(&hash_keys, 0, sizeof(hash_keys));
+ skb_flow_dissect_flow_keys(skb, &keys, 0);
+
+ if (!(keys.control.flags & FLOW_DIS_ENCAPSULATION))
+ return 0;
+
+ if (keys.control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP)
+ hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP)
+ hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst;
+ } else if (keys.control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
+ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP)
+ hash_keys.addrs.v6addrs.src = keys.addrs.v6addrs.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP)
+ hash_keys.addrs.v6addrs.dst = keys.addrs.v6addrs.dst;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_FLOWLABEL)
+ hash_keys.tags.flow_label = keys.tags.flow_label;
+ }
+
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO)
+ hash_keys.basic.ip_proto = keys.basic.ip_proto;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_PORT)
+ hash_keys.ports.src = keys.ports.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_PORT)
+ hash_keys.ports.dst = keys.ports.dst;
+
+ return flow_hash_from_keys(&hash_keys);
+}
+
+static u32 fib_multipath_custom_hash_skb(const struct net *net,
+ const struct sk_buff *skb)
+{
+ u32 mhash, mhash_inner;
+ bool has_inner = true;
+
+ mhash = fib_multipath_custom_hash_outer(net, skb, &has_inner);
+ mhash_inner = fib_multipath_custom_hash_inner(net, skb, has_inner);
+
+ return jhash_2words(mhash, mhash_inner, 0);
+}
+
+static u32 fib_multipath_custom_hash_fl4(const struct net *net,
+ const struct flowi4 *fl4)
+{
+ u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+ struct flow_keys hash_keys;
+
+ if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_OUTER_MASK))
+ return 0;
+
+ memset(&hash_keys, 0, sizeof(hash_keys));
+ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP)
+ hash_keys.addrs.v4addrs.src = fl4->saddr;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP)
+ hash_keys.addrs.v4addrs.dst = fl4->daddr;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+ hash_keys.basic.ip_proto = fl4->flowi4_proto;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
+ hash_keys.ports.src = fl4->fl4_sport;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+ hash_keys.ports.dst = fl4->fl4_dport;
+
+ return flow_hash_from_keys(&hash_keys);
+}
+
/* if skb is set it will be used and fl4 can be NULL */
int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
const struct sk_buff *skb, struct flow_keys *flkeys)
{
u32 multipath_hash = fl4 ? fl4->flowi4_multipath_hash : 0;
struct flow_keys hash_keys;
- u32 mhash;
+ u32 mhash = 0;
switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
case 0:
@@ -1924,6 +2039,7 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
hash_keys.addrs.v4addrs.src = fl4->saddr;
hash_keys.addrs.v4addrs.dst = fl4->daddr;
}
+ mhash = flow_hash_from_keys(&hash_keys);
break;
case 1:
/* skb is currently provided only when forwarding */
@@ -1957,6 +2073,7 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
hash_keys.ports.dst = fl4->fl4_dport;
hash_keys.basic.ip_proto = fl4->flowi4_proto;
}
+ mhash = flow_hash_from_keys(&hash_keys);
break;
case 2:
memset(&hash_keys, 0, sizeof(hash_keys));
@@ -1987,9 +2104,15 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
hash_keys.addrs.v4addrs.src = fl4->saddr;
hash_keys.addrs.v4addrs.dst = fl4->daddr;
}
+ mhash = flow_hash_from_keys(&hash_keys);
+ break;
+ case 3:
+ if (skb)
+ mhash = fib_multipath_custom_hash_skb(net, skb);
+ else
+ mhash = fib_multipath_custom_hash_fl4(net, fl4);
break;
}
- mhash = flow_hash_from_keys(&hash_keys);
if (multipath_hash)
mhash = jhash_2words(mhash, multipath_hash, 0);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index a62934b9f15a..4fa77f182dcb 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -19,6 +19,7 @@
#include <net/snmp.h>
#include <net/icmp.h>
#include <net/ip.h>
+#include <net/ip_fib.h>
#include <net/route.h>
#include <net/tcp.h>
#include <net/udp.h>
@@ -29,6 +30,7 @@
#include <net/netevent.h>
static int two = 2;
+static int three __maybe_unused = 3;
static int four = 4;
static int thousand = 1000;
static int tcp_retr1_max = 255;
@@ -48,6 +50,8 @@ static int ip_ping_group_range_min[] = { 0, 0 };
static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
static u32 u32_max_div_HZ = UINT_MAX / HZ;
static int one_day_secs = 24 * 3600;
+static u32 fib_multipath_hash_fields_all_mask __maybe_unused =
+ FIB_MULTIPATH_HASH_FIELD_ALL_MASK;
/* obsolete */
static int sysctl_tcp_low_latency __read_mostly;
@@ -461,6 +465,22 @@ static int proc_fib_multipath_hash_policy(struct ctl_table *table, int write,
return ret;
}
+
+static int proc_fib_multipath_hash_fields(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ struct net *net;
+ int ret;
+
+ net = container_of(table->data, struct net,
+ ipv4.sysctl_fib_multipath_hash_fields);
+ ret = proc_douintvec_minmax(table, write, buffer, lenp, ppos);
+ if (write && ret == 0)
+ call_netevent_notifiers(NETEVENT_IPV4_MPATH_HASH_UPDATE, net);
+
+ return ret;
+}
#endif
static struct ctl_table ipv4_table[] = {
@@ -1050,7 +1070,16 @@ static struct ctl_table ipv4_net_table[] = {
.mode = 0644,
.proc_handler = proc_fib_multipath_hash_policy,
.extra1 = SYSCTL_ZERO,
- .extra2 = &two,
+ .extra2 = &three,
+ },
+ {
+ .procname = "fib_multipath_hash_fields",
+ .data = &init_net.ipv4.sysctl_fib_multipath_hash_fields,
+ .maxlen = sizeof(u32),
+ .mode = 0644,
+ .proc_handler = proc_fib_multipath_hash_fields,
+ .extra1 = SYSCTL_ONE,
+ .extra2 = &fib_multipath_hash_fields_all_mask,
},
#endif
{
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 4cf4dd532d1c..cd52ce0a2a85 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5885,6 +5885,7 @@ step5:
return;
csum_error:
+ trace_tcp_bad_csum(skb);
TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS);
TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 312184cead57..4f5b68a90be9 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1731,6 +1731,7 @@ discard:
return 0;
csum_err:
+ trace_tcp_bad_csum(skb);
TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS);
TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS);
goto discard;
@@ -1801,6 +1802,7 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
if (unlikely(tcp_checksum_complete(skb))) {
bh_unlock_sock(sk);
+ trace_tcp_bad_csum(skb);
__TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS);
__TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS);
return true;
@@ -2098,6 +2100,7 @@ no_tcp_socket:
if (tcp_checksum_complete(skb)) {
csum_error:
+ trace_tcp_bad_csum(skb);
__TCP_INC_STATS(net, TCP_MIB_CSUMERRORS);
bad_packet:
__TCP_INC_STATS(net, TCP_MIB_INERRS);
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c
index e44aaf41a138..5048c47c79b2 100644
--- a/net/ipv4/tunnel4.c
+++ b/net/ipv4/tunnel4.c
@@ -218,7 +218,6 @@ static const struct net_protocol tunnel4_protocol = {
.handler = tunnel4_rcv,
.err_handler = tunnel4_err,
.no_policy = 1,
- .netns_ok = 1,
};
#if IS_ENABLED(CONFIG_IPV6)
@@ -226,7 +225,6 @@ static const struct net_protocol tunnel64_protocol = {
.handler = tunnel64_rcv,
.err_handler = tunnel64_err,
.no_policy = 1,
- .netns_ok = 1,
};
#endif
@@ -235,7 +233,6 @@ static const struct net_protocol tunnelmpls4_protocol = {
.handler = tunnelmpls4_rcv,
.err_handler = tunnelmpls4_err,
.no_policy = 1,
- .netns_ok = 1,
};
#endif
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index bd8773b49e72..cd1cd68adeec 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -31,7 +31,6 @@ static const struct net_protocol udplite_protocol = {
.handler = udplite_rcv,
.err_handler = udplite_err,
.no_policy = 1,
- .netns_ok = 1,
};
struct proto udplite_prot = {
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c
index ea595c8549c7..2fe5860c21d6 100644
--- a/net/ipv4/xfrm4_protocol.c
+++ b/net/ipv4/xfrm4_protocol.c
@@ -181,21 +181,18 @@ static const struct net_protocol esp4_protocol = {
.handler = xfrm4_esp_rcv,
.err_handler = xfrm4_esp_err,
.no_policy = 1,
- .netns_ok = 1,
};
static const struct net_protocol ah4_protocol = {
.handler = xfrm4_ah_rcv,
.err_handler = xfrm4_ah_err,
.no_policy = 1,
- .netns_ok = 1,
};
static const struct net_protocol ipcomp4_protocol = {
.handler = xfrm4_ipcomp_rcv,
.err_handler = xfrm4_ipcomp_err,
.no_policy = 1,
- .netns_ok = 1,
};
static const struct xfrm_input_afinfo xfrm4_input_afinfo = {
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 679699e953f1..2d650dc24349 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -32,6 +32,7 @@
#include <net/lwtunnel.h>
#include <net/fib_notifier.h>
+#include <net/ip_fib.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
@@ -2355,6 +2356,10 @@ static int __net_init fib6_net_init(struct net *net)
if (err)
return err;
+ /* Default to 3-tuple */
+ net->ipv6.sysctl.multipath_hash_fields =
+ FIB_MULTIPATH_HASH_FIELD_DEFAULT_MASK;
+
spin_lock_init(&net->ipv6.fib6_gc_lock);
rwlock_init(&net->ipv6.fib6_walker_lock);
INIT_LIST_HEAD(&net->ipv6.fib6_walkers);
@@ -2362,7 +2367,7 @@ static int __net_init fib6_net_init(struct net *net)
net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
if (!net->ipv6.rt6_stats)
- goto out_timer;
+ goto out_notifier;
/* Avoid false sharing : Use at least a full cache line */
size = max_t(size_t, size, L1_CACHE_BYTES);
@@ -2407,7 +2412,7 @@ out_fib_table_hash:
kfree(net->ipv6.fib_table_hash);
out_rt6_stats:
kfree(net->ipv6.rt6_stats);
-out_timer:
+out_notifier:
fib6_notifier_exit(net);
return -ENOMEM;
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a22822bdbf39..c46889381ae4 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2326,12 +2326,131 @@ out:
}
}
+static u32 rt6_multipath_custom_hash_outer(const struct net *net,
+ const struct sk_buff *skb,
+ bool *p_has_inner)
+{
+ u32 hash_fields = ip6_multipath_hash_fields(net);
+ struct flow_keys keys, hash_keys;
+
+ if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_OUTER_MASK))
+ return 0;
+
+ memset(&hash_keys, 0, sizeof(hash_keys));
+ skb_flow_dissect_flow_keys(skb, &keys, FLOW_DISSECTOR_F_STOP_AT_ENCAP);
+
+ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP)
+ hash_keys.addrs.v6addrs.src = keys.addrs.v6addrs.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP)
+ hash_keys.addrs.v6addrs.dst = keys.addrs.v6addrs.dst;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+ hash_keys.basic.ip_proto = keys.basic.ip_proto;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_FLOWLABEL)
+ hash_keys.tags.flow_label = keys.tags.flow_label;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
+ hash_keys.ports.src = keys.ports.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+ hash_keys.ports.dst = keys.ports.dst;
+
+ *p_has_inner = !!(keys.control.flags & FLOW_DIS_ENCAPSULATION);
+ return flow_hash_from_keys(&hash_keys);
+}
+
+static u32 rt6_multipath_custom_hash_inner(const struct net *net,
+ const struct sk_buff *skb,
+ bool has_inner)
+{
+ u32 hash_fields = ip6_multipath_hash_fields(net);
+ struct flow_keys keys, hash_keys;
+
+ /* We assume the packet carries an encapsulation, but if none was
+ * encountered during dissection of the outer flow, then there is no
+ * point in calling the flow dissector again.
+ */
+ if (!has_inner)
+ return 0;
+
+ if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_MASK))
+ return 0;
+
+ memset(&hash_keys, 0, sizeof(hash_keys));
+ skb_flow_dissect_flow_keys(skb, &keys, 0);
+
+ if (!(keys.control.flags & FLOW_DIS_ENCAPSULATION))
+ return 0;
+
+ if (keys.control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP)
+ hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP)
+ hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst;
+ } else if (keys.control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
+ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP)
+ hash_keys.addrs.v6addrs.src = keys.addrs.v6addrs.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP)
+ hash_keys.addrs.v6addrs.dst = keys.addrs.v6addrs.dst;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_FLOWLABEL)
+ hash_keys.tags.flow_label = keys.tags.flow_label;
+ }
+
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO)
+ hash_keys.basic.ip_proto = keys.basic.ip_proto;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_PORT)
+ hash_keys.ports.src = keys.ports.src;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_PORT)
+ hash_keys.ports.dst = keys.ports.dst;
+
+ return flow_hash_from_keys(&hash_keys);
+}
+
+static u32 rt6_multipath_custom_hash_skb(const struct net *net,
+ const struct sk_buff *skb)
+{
+ u32 mhash, mhash_inner;
+ bool has_inner = true;
+
+ mhash = rt6_multipath_custom_hash_outer(net, skb, &has_inner);
+ mhash_inner = rt6_multipath_custom_hash_inner(net, skb, has_inner);
+
+ return jhash_2words(mhash, mhash_inner, 0);
+}
+
+static u32 rt6_multipath_custom_hash_fl6(const struct net *net,
+ const struct flowi6 *fl6)
+{
+ u32 hash_fields = ip6_multipath_hash_fields(net);
+ struct flow_keys hash_keys;
+
+ if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_OUTER_MASK))
+ return 0;
+
+ memset(&hash_keys, 0, sizeof(hash_keys));
+ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP)
+ hash_keys.addrs.v6addrs.src = fl6->saddr;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP)
+ hash_keys.addrs.v6addrs.dst = fl6->daddr;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+ hash_keys.basic.ip_proto = fl6->flowi6_proto;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_FLOWLABEL)
+ hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
+ hash_keys.ports.src = fl6->fl6_sport;
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+ hash_keys.ports.dst = fl6->fl6_dport;
+
+ return flow_hash_from_keys(&hash_keys);
+}
+
/* if skb is set it will be used and fl6 can be NULL */
u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
const struct sk_buff *skb, struct flow_keys *flkeys)
{
struct flow_keys hash_keys;
- u32 mhash;
+ u32 mhash = 0;
switch (ip6_multipath_hash_policy(net)) {
case 0:
@@ -2345,6 +2464,7 @@ u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
hash_keys.basic.ip_proto = fl6->flowi6_proto;
}
+ mhash = flow_hash_from_keys(&hash_keys);
break;
case 1:
if (skb) {
@@ -2376,6 +2496,7 @@ u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
hash_keys.ports.dst = fl6->fl6_dport;
hash_keys.basic.ip_proto = fl6->flowi6_proto;
}
+ mhash = flow_hash_from_keys(&hash_keys);
break;
case 2:
memset(&hash_keys, 0, sizeof(hash_keys));
@@ -2412,9 +2533,15 @@ u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
hash_keys.basic.ip_proto = fl6->flowi6_proto;
}
+ mhash = flow_hash_from_keys(&hash_keys);
+ break;
+ case 3:
+ if (skb)
+ mhash = rt6_multipath_custom_hash_skb(net, skb);
+ else
+ mhash = rt6_multipath_custom_hash_fl6(net, fl6);
break;
}
- mhash = flow_hash_from_keys(&hash_keys);
return mhash >> 1;
}
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 27102c3d6e1d..d7cf26f730d7 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -17,13 +17,17 @@
#include <net/addrconf.h>
#include <net/inet_frag.h>
#include <net/netevent.h>
+#include <net/ip_fib.h>
#ifdef CONFIG_NETLABEL
#include <net/calipso.h>
#endif
static int two = 2;
+static int three = 3;
static int flowlabel_reflect_max = 0x7;
static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
+static u32 rt6_multipath_hash_fields_all_mask =
+ FIB_MULTIPATH_HASH_FIELD_ALL_MASK;
static int proc_rt6_multipath_hash_policy(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
@@ -40,6 +44,22 @@ static int proc_rt6_multipath_hash_policy(struct ctl_table *table, int write,
return ret;
}
+static int
+proc_rt6_multipath_hash_fields(struct ctl_table *table, int write, void *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ struct net *net;
+ int ret;
+
+ net = container_of(table->data, struct net,
+ ipv6.sysctl.multipath_hash_fields);
+ ret = proc_douintvec_minmax(table, write, buffer, lenp, ppos);
+ if (write && ret == 0)
+ call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net);
+
+ return ret;
+}
+
static struct ctl_table ipv6_table_template[] = {
{
.procname = "bindv6only",
@@ -149,7 +169,16 @@ static struct ctl_table ipv6_table_template[] = {
.mode = 0644,
.proc_handler = proc_rt6_multipath_hash_policy,
.extra1 = SYSCTL_ZERO,
- .extra2 = &two,
+ .extra2 = &three,
+ },
+ {
+ .procname = "fib_multipath_hash_fields",
+ .data = &init_net.ipv6.sysctl.multipath_hash_fields,
+ .maxlen = sizeof(u32),
+ .mode = 0644,
+ .proc_handler = proc_rt6_multipath_hash_fields,
+ .extra1 = SYSCTL_ONE,
+ .extra2 = &rt6_multipath_hash_fields_all_mask,
},
{
.procname = "seg6_flowlabel",
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5f47c0b6e3de..4435fa342e7a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1538,6 +1538,7 @@ discard:
kfree_skb(skb);
return 0;
csum_err:
+ trace_tcp_bad_csum(skb);
TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS);
TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS);
goto discard;
@@ -1754,6 +1755,7 @@ no_tcp_socket:
if (tcp_checksum_complete(skb)) {
csum_error:
+ trace_tcp_bad_csum(skb);
__TCP_INC_STATS(net, TCP_MIB_CSUMERRORS);
bad_packet:
__TCP_INC_STATS(net, TCP_MIB_INERRS);
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 97ae1255fcb6..536c30d4dd7d 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -635,7 +635,6 @@ static struct inet_protosw l2tp_ip_protosw = {
static struct net_protocol l2tp_ip_protocol __read_mostly = {
.handler = l2tp_ip_recv,
- .netns_ok = 1,
};
static int __init l2tp_ip_init(void)
diff --git a/net/netlabel/netlabel_calipso.c b/net/netlabel/netlabel_calipso.c
index f28c8947c730..91a19c3ea1a3 100644
--- a/net/netlabel/netlabel_calipso.c
+++ b/net/netlabel/netlabel_calipso.c
@@ -105,7 +105,7 @@ static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NLBL_CALIPSO_A_MTYPE])
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) {
case CALIPSO_MAP_PASS:
ret_val = netlbl_calipso_add_pass(info, &audit_info);
@@ -287,7 +287,7 @@ static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NLBL_CALIPSO_A_DOI])
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
cb_arg.doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
cb_arg.audit_info = &audit_info;
ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 4f50a64315cf..baf235721c43 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -410,7 +410,7 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NLBL_CIPSOV4_A_MTYPE])
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
case CIPSO_V4_MAP_TRANS:
ret_val = netlbl_cipsov4_add_std(info, &audit_info);
@@ -709,7 +709,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NLBL_CIPSOV4_A_DOI])
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
cb_arg.audit_info = &audit_info;
ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index ca52f5085989..e664ab990941 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -434,7 +434,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
(info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
return netlbl_mgmt_add_common(info, &audit_info);
}
@@ -457,7 +457,7 @@ static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NLBL_MGMT_A_DOMAIN])
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
@@ -557,7 +557,7 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
(info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
return netlbl_mgmt_add_common(info, &audit_info);
}
@@ -576,7 +576,7 @@ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
{
struct netlbl_audit audit_info;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
}
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 3e6ac9b790b1..2483df0bbd7c 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -814,7 +814,7 @@ static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
if (value == 1 || value == 0) {
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
netlbl_unlabel_acceptflg_set(value, &audit_info);
return 0;
}
@@ -897,7 +897,7 @@ static int netlbl_unlabel_staticadd(struct sk_buff *skb,
!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
if (ret_val != 0)
@@ -947,7 +947,7 @@ static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
if (ret_val != 0)
@@ -994,7 +994,7 @@ static int netlbl_unlabel_staticremove(struct sk_buff *skb,
!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
if (ret_val != 0)
@@ -1034,7 +1034,7 @@ static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
return -EINVAL;
- netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_netlink_auditinfo(&audit_info);
ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
if (ret_val != 0)
diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
index b9ba8112b3c5..6190cbf94bf0 100644
--- a/net/netlabel/netlabel_user.h
+++ b/net/netlabel/netlabel_user.h
@@ -28,11 +28,9 @@
/**
* netlbl_netlink_auditinfo - Fetch the audit information from a NETLINK msg
- * @skb: the packet
* @audit_info: NetLabel audit information
*/
-static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
- struct netlbl_audit *audit_info)
+static inline void netlbl_netlink_auditinfo(struct netlbl_audit *audit_info)
{
security_task_getsecid_subj(current, &audit_info->secid);
audit_info->loginuid = audit_get_loginuid(current);
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index cadb6a29b285..1b5eae57bc90 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -967,8 +967,7 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
/* Associate skb with specified zone. */
if (tmpl) {
- if (skb_nfct(skb))
- nf_conntrack_put(skb_nfct(skb));
+ nf_conntrack_put(skb_nfct(skb));
nf_conntrack_get(&tmpl->ct_general);
nf_ct_set(skb, tmpl, IP_CT_NEW);
}
@@ -1329,11 +1328,9 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
int ovs_ct_clear(struct sk_buff *skb, struct sw_flow_key *key)
{
- if (skb_nfct(skb)) {
- nf_conntrack_put(skb_nfct(skb));
- nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
- ovs_ct_fill_key(skb, key, false);
- }
+ nf_conntrack_put(skb_nfct(skb));
+ nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
+ ovs_ct_fill_key(skb, key, false);
return 0;
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ba96db1880ea..597d798ac0a5 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3923,12 +3923,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
return -EFAULT;
lock_sock(sk);
- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
- ret = -EBUSY;
- } else {
+ if (!po->rx_ring.pg_vec && !po->tx_ring.pg_vec)
po->tp_tx_has_off = !!val;
- ret = 0;
- }
+
release_sock(sk);
return 0;
}
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index 5c91df52b8c2..66fe2b82af9a 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -114,9 +114,6 @@ static void taprio_free_sched_cb(struct rcu_head *head)
struct sched_gate_list *sched = container_of(head, struct sched_gate_list, rcu);
struct sched_entry *entry, *n;
- if (!sched)
- return;
-
list_for_each_entry_safe(entry, n, &sched->entries, list) {
list_del(&entry->list);
kfree(entry);
@@ -438,6 +435,11 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
struct Qdisc *child;
int queue;
+ if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) {
+ WARN_ONCE(1, "Trying to enqueue skb into the root of a taprio qdisc configured with full offload\n");
+ return qdisc_drop(skb, sch, to_free);
+ }
+
queue = skb_get_queue_mapping(skb);
child = q->qdiscs[queue];
@@ -529,23 +531,7 @@ static struct sk_buff *taprio_peek_soft(struct Qdisc *sch)
static struct sk_buff *taprio_peek_offload(struct Qdisc *sch)
{
- struct taprio_sched *q = qdisc_priv(sch);
- struct net_device *dev = qdisc_dev(sch);
- struct sk_buff *skb;
- int i;
-
- for (i = 0; i < dev->num_tx_queues; i++) {
- struct Qdisc *child = q->qdiscs[i];
-
- if (unlikely(!child))
- continue;
-
- skb = child->ops->peek(child);
- if (!skb)
- continue;
-
- return skb;
- }
+ WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n");
return NULL;
}
@@ -654,27 +640,7 @@ done:
static struct sk_buff *taprio_dequeue_offload(struct Qdisc *sch)
{
- struct taprio_sched *q = qdisc_priv(sch);
- struct net_device *dev = qdisc_dev(sch);
- struct sk_buff *skb;
- int i;
-
- for (i = 0; i < dev->num_tx_queues; i++) {
- struct Qdisc *child = q->qdiscs[i];
-
- if (unlikely(!child))
- continue;
-
- skb = child->ops->dequeue(child);
- if (unlikely(!skb))
- continue;
-
- qdisc_bstats_update(sch, skb);
- qdisc_qstats_backlog_dec(sch, skb);
- sch->q.qlen--;
-
- return skb;
- }
+ WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n");
return NULL;
}
@@ -1759,6 +1725,37 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
return taprio_change(sch, opt, extack);
}
+static void taprio_attach(struct Qdisc *sch)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ unsigned int ntx;
+
+ /* Attach underlying qdisc */
+ for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
+ struct Qdisc *qdisc = q->qdiscs[ntx];
+ struct Qdisc *old;
+
+ if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
+ qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
+ old = dev_graft_qdisc(qdisc->dev_queue, qdisc);
+ if (ntx < dev->real_num_tx_queues)
+ qdisc_hash_add(qdisc, false);
+ } else {
+ old = dev_graft_qdisc(qdisc->dev_queue, sch);
+ qdisc_refcount_inc(sch);
+ }
+ if (old)
+ qdisc_put(old);
+ }
+
+ /* access to the child qdiscs is not needed in offload mode */
+ if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
+ kfree(q->qdiscs);
+ q->qdiscs = NULL;
+ }
+}
+
static struct netdev_queue *taprio_queue_get(struct Qdisc *sch,
unsigned long cl)
{
@@ -1785,8 +1782,12 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl,
if (dev->flags & IFF_UP)
dev_deactivate(dev);
- *old = q->qdiscs[cl - 1];
- q->qdiscs[cl - 1] = new;
+ if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
+ *old = dev_graft_qdisc(dev_queue, new);
+ } else {
+ *old = q->qdiscs[cl - 1];
+ q->qdiscs[cl - 1] = new;
+ }
if (new)
new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
@@ -2020,6 +2021,7 @@ static struct Qdisc_ops taprio_qdisc_ops __read_mostly = {
.change = taprio_change,
.destroy = taprio_destroy,
.reset = taprio_reset,
+ .attach = taprio_attach,
.peek = taprio_peek,
.dequeue = taprio_dequeue,
.enqueue = taprio_enqueue,
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 6f2bbfeec3a4..baa4e770e4ba 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1171,7 +1171,6 @@ static const struct net_protocol sctp_protocol = {
.handler = sctp4_rcv,
.err_handler = sctp_v4_err,
.no_policy = 1,
- .netns_ok = 1,
.icmp_strict_tag_validation = 1,
};
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 1dcb34dfd56b..7b59ec9a24c5 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -2018,8 +2018,7 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,
if (copied < 0)
goto splice_read_end;
- if (likely(!(flags & MSG_PEEK)))
- tls_sw_advance_skb(sk, skb, copied);
+ tls_sw_advance_skb(sk, skb, copied);
splice_read_end:
release_sock(sk);
diff --git a/tools/testing/selftests/drivers/net/mlxsw/port_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/port_scale.sh
index 65f43a7ce9c9..1e9a4aff76a2 100644
--- a/tools/testing/selftests/drivers/net/mlxsw/port_scale.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/port_scale.sh
@@ -7,6 +7,8 @@
PORT_NUM_NETIFS=0
+declare -a unsplit
+
port_setup_prepare()
{
:
@@ -20,12 +22,12 @@ port_cleanup()
devlink port unsplit $port
check_err $? "Did not unsplit $netdev"
done
+ unsplit=()
}
split_all_ports()
{
local should_fail=$1; shift
- local -a unsplit
# Loop over the splittable netdevs and create tuples of netdev along
# with its width. For example:
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_headroom.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_headroom.sh
index 27de3d9ed08e..f4493ef9cca1 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/qos_headroom.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/qos_headroom.sh
@@ -29,37 +29,38 @@ cleanup()
get_prio_pg()
{
- __mlnx_qos -i $swp | sed -n '/^PFC/,/^[^[:space:]]/p' |
- grep buffer | sed 's/ \+/ /g' | cut -d' ' -f 2-
+ # Produces a string of numbers "<B0> <B1> ... <B7> ", where BX is number
+ # of buffer that priority X is mapped to.
+ dcb -j buffer show dev $swp |
+ jq -r '[.prio_buffer | .[] | tostring + " "] | add'
}
get_prio_pfc()
{
- __mlnx_qos -i $swp | sed -n '/^PFC/,/^[^[:space:]]/p' |
- grep enabled | sed 's/ \+/ /g' | cut -d' ' -f 2-
+ # Produces a string of numbers "<P0> <P1> ... <P7> ", where PX denotes
+ # whether priority X has PFC enabled (the value is 1) or disabled (0).
+ dcb -j pfc show dev $swp |
+ jq -r '[.prio_pfc | .[] | if . then "1 " else "0 " end] | add'
}
get_prio_tc()
{
- __mlnx_qos -i $swp | sed -n '/^tc/,$p' |
- awk '/^tc/ { TC = $2 }
- /priority:/ { PRIO[$2]=TC }
- END {
- for (i in PRIO)
- printf("%d ", PRIO[i])
- }'
+ # Produces a string of numbers "<T0> <T1> ... <T7> ", where TC is number
+ # of TC that priority X is mapped to.
+ dcb -j ets show dev $swp |
+ jq -r '[.prio_tc | .[] | tostring + " "] | add'
}
get_buf_size()
{
local idx=$1; shift
- __mlnx_qos -i $swp | grep Receive | sed 's/.*: //' | cut -d, -f $((idx + 1))
+ dcb -j buffer show dev $swp | jq ".buffer_size[$idx]"
}
get_tot_size()
{
- __mlnx_qos -i $swp | grep Receive | sed 's/.*total_size=//'
+ dcb -j buffer show dev $swp | jq '.total_size'
}
check_prio_pg()
@@ -121,18 +122,18 @@ test_dcb_ets()
{
RET=0
- __mlnx_qos -i $swp --prio_tc=0,2,4,6,1,3,5,7 > /dev/null
+ dcb ets set dev $swp prio-tc 0:0 1:2 2:4 3:6 4:1 5:3 6:5 7:7
check_prio_pg "0 2 4 6 1 3 5 7 "
check_prio_tc "0 2 4 6 1 3 5 7 "
check_prio_pfc "0 0 0 0 0 0 0 0 "
- __mlnx_qos -i $swp --prio_tc=0,0,0,0,0,0,0,0 > /dev/null
+ dcb ets set dev $swp prio-tc all:0
check_prio_pg "0 0 0 0 0 0 0 0 "
check_prio_tc "0 0 0 0 0 0 0 0 "
- __mlnx_qos -i $swp --prio2buffer=1,3,5,7,0,2,4,6 &> /dev/null
+ dcb buffer set dev $swp prio-buffer 0:1 1:3 2:5 3:7 4:0 5:2 6:4 7:6 2>/dev/null
check_fail $? "prio2buffer accepted in DCB mode"
log_test "Configuring headroom through ETS"
@@ -174,7 +175,7 @@ test_pfc()
{
RET=0
- __mlnx_qos -i $swp --prio_tc=0,0,0,0,0,1,2,3 > /dev/null
+ dcb ets set dev $swp prio-tc all:0 5:1 6:2 7:3
local buf0size=$(get_buf_size 0)
local buf1size=$(get_buf_size 1)
@@ -193,7 +194,7 @@ test_pfc()
RET=0
- __mlnx_qos -i $swp --pfc=0,0,0,0,0,1,1,1 --cable_len=0 > /dev/null
+ dcb pfc set dev $swp prio-pfc all:off 5:on 6:on 7:on delay 0
check_prio_pg "0 0 0 0 0 1 2 3 "
check_prio_pfc "0 0 0 0 0 1 1 1 "
@@ -210,7 +211,7 @@ test_pfc()
RET=0
- __mlnx_qos -i $swp --pfc=0,0,0,0,0,1,1,1 --cable_len=1000 > /dev/null
+ dcb pfc set dev $swp delay 1000
check_buf_size 0 "== $buf0size"
check_buf_size 1 "> $buf1size"
@@ -221,8 +222,8 @@ test_pfc()
RET=0
- __mlnx_qos -i $swp --pfc=0,0,0,0,0,0,0,0 --cable_len=0 > /dev/null
- __mlnx_qos -i $swp --prio_tc=0,0,0,0,0,0,0,0 > /dev/null
+ dcb pfc set dev $swp prio-pfc all:off delay 0
+ dcb ets set dev $swp prio-tc all:0
check_prio_pg "0 0 0 0 0 0 0 0 "
check_prio_tc "0 0 0 0 0 0 0 0 "
@@ -242,13 +243,13 @@ test_tc_priomap()
{
RET=0
- __mlnx_qos -i $swp --prio_tc=0,1,2,3,4,5,6,7 > /dev/null
+ dcb ets set dev $swp prio-tc 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7
check_prio_pg "0 1 2 3 4 5 6 7 "
tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
check_prio_pg "0 0 0 0 0 0 0 0 "
- __mlnx_qos -i $swp --prio2buffer=1,3,5,7,0,2,4,6 > /dev/null
+ dcb buffer set dev $swp prio-buffer 0:1 1:3 2:5 3:7 4:0 5:2 6:4 7:6
check_prio_pg "1 3 5 7 0 2 4 6 "
tc qdisc delete dev $swp root
@@ -256,9 +257,9 @@ test_tc_priomap()
# Clean up.
tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
- __mlnx_qos -i $swp --prio2buffer=0,0,0,0,0,0,0,0 > /dev/null
+ dcb buffer set dev $swp prio-buffer all:0
tc qdisc delete dev $swp root
- __mlnx_qos -i $swp --prio_tc=0,0,0,0,0,0,0,0 > /dev/null
+ dcb ets set dev $swp prio-tc all:0
log_test "TC: priomap"
}
@@ -270,12 +271,12 @@ test_tc_sizes()
RET=0
- __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 &> /dev/null
+ dcb buffer set dev $swp buffer-size all:0 0:$size 2>/dev/null
check_fail $? "buffer_size should fail before qdisc is added"
tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
- __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 > /dev/null
+ dcb buffer set dev $swp buffer-size all:0 0:$size
check_err $? "buffer_size should pass after qdisc is added"
check_buf_size 0 "== $size" "set size: "
@@ -283,26 +284,26 @@ test_tc_sizes()
check_buf_size 0 "== $size" "set MTU: "
mtu_restore $swp
- __mlnx_qos -i $swp --buffer_size=0,0,0,0,0,0,0,0 > /dev/null
+ dcb buffer set dev $swp buffer-size all:0
# After replacing the qdisc for the same kind, buffer_size still has to
# work.
tc qdisc replace dev $swp root handle 1: bfifo limit 1M
- __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 > /dev/null
+ dcb buffer set dev $swp buffer-size all:0 0:$size
check_buf_size 0 "== $size" "post replace, set size: "
- __mlnx_qos -i $swp --buffer_size=0,0,0,0,0,0,0,0 > /dev/null
+ dcb buffer set dev $swp buffer-size all:0
# Likewise after replacing for a different kind.
tc qdisc replace dev $swp root handle 2: prio bands 8
- __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 > /dev/null
+ dcb buffer set dev $swp buffer-size all:0 0:$size
check_buf_size 0 "== $size" "post replace different kind, set size: "
tc qdisc delete dev $swp root
- __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 &> /dev/null
+ dcb buffer set dev $swp buffer-size all:0 0:$size 2>/dev/null
check_fail $? "buffer_size should fail after qdisc is deleted"
log_test "TC: buffer size"
@@ -363,10 +364,10 @@ test_tc_int_buf()
tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
test_int_buf "TC: "
- __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 > /dev/null
+ dcb buffer set dev $swp buffer-size all:0 0:$size
test_int_buf "TC+buffsize: "
- __mlnx_qos -i $swp --buffer_size=0,0,0,0,0,0,0,0 > /dev/null
+ dcb buffer set dev $swp buffer-size all:0
tc qdisc delete dev $swp root
}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh
index 0bf76f13c030..faa51012cdac 100644
--- a/tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh
@@ -82,17 +82,3 @@ bail_on_lldpad()
fi
fi
}
-
-__mlnx_qos()
-{
- local err
-
- mlnx_qos "$@" 2>/dev/null
- err=$?
-
- if ((err)); then
- echo "Error ($err) in mlnx_qos $@" >/dev/stderr
- fi
-
- return $err
-}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_pfc.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_pfc.sh
index 5c7700212f75..5d5622fc2758 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/qos_pfc.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/qos_pfc.sh
@@ -171,7 +171,7 @@ switch_create()
# assignment.
tc qdisc replace dev $swp1 root handle 1: \
ets bands 8 strict 8 priomap 7 6
- __mlnx_qos -i $swp1 --prio2buffer=0,1,0,0,0,0,0,0 >/dev/null
+ dcb buffer set dev $swp1 prio-buffer all:0 1:1
# $swp2
# -----
@@ -209,8 +209,8 @@ switch_create()
# the lossless prio into a buffer of its own. Don't bother with buffer
# sizes though, there is not going to be any pressure in the "backward"
# direction.
- __mlnx_qos -i $swp3 --prio2buffer=0,1,0,0,0,0,0,0 >/dev/null
- __mlnx_qos -i $swp3 --pfc=0,1,0,0,0,0,0,0 >/dev/null
+ dcb buffer set dev $swp3 prio-buffer all:0 1:1
+ dcb pfc set dev $swp3 prio-pfc all:off 1:on
# $swp4
# -----
@@ -226,11 +226,11 @@ switch_create()
# Configure qdisc so that we can hand-tune headroom.
tc qdisc replace dev $swp4 root handle 1: \
ets bands 8 strict 8 priomap 7 6
- __mlnx_qos -i $swp4 --prio2buffer=0,1,0,0,0,0,0,0 >/dev/null
- __mlnx_qos -i $swp4 --pfc=0,1,0,0,0,0,0,0 >/dev/null
+ dcb buffer set dev $swp4 prio-buffer all:0 1:1
+ dcb pfc set dev $swp4 prio-pfc all:off 1:on
# PG0 will get autoconfigured to Xoff, give PG1 arbitrarily 100K, which
# is (-2*MTU) about 80K of delay provision.
- __mlnx_qos -i $swp4 --buffer_size=0,$_100KB,0,0,0,0,0,0 >/dev/null
+ dcb buffer set dev $swp4 buffer-size all:0 1:$_100KB
# bridges
# -------
@@ -273,9 +273,9 @@ switch_destroy()
# $swp4
# -----
- __mlnx_qos -i $swp4 --buffer_size=0,0,0,0,0,0,0,0 >/dev/null
- __mlnx_qos -i $swp4 --pfc=0,0,0,0,0,0,0,0 >/dev/null
- __mlnx_qos -i $swp4 --prio2buffer=0,0,0,0,0,0,0,0 >/dev/null
+ dcb buffer set dev $swp4 buffer-size all:0
+ dcb pfc set dev $swp4 prio-pfc all:off
+ dcb buffer set dev $swp4 prio-buffer all:0
tc qdisc del dev $swp4 root
devlink_tc_bind_pool_th_restore $swp4 1 ingress
@@ -288,8 +288,8 @@ switch_destroy()
# $swp3
# -----
- __mlnx_qos -i $swp3 --pfc=0,0,0,0,0,0,0,0 >/dev/null
- __mlnx_qos -i $swp3 --prio2buffer=0,0,0,0,0,0,0,0 >/dev/null
+ dcb pfc set dev $swp3 prio-pfc all:off
+ dcb buffer set dev $swp3 prio-buffer all:0
tc qdisc del dev $swp3 root
devlink_tc_bind_pool_th_restore $swp3 1 egress
@@ -315,7 +315,7 @@ switch_destroy()
# $swp1
# -----
- __mlnx_qos -i $swp1 --prio2buffer=0,0,0,0,0,0,0,0 >/dev/null
+ dcb buffer set dev $swp1 prio-buffer all:0
tc qdisc del dev $swp1 root
devlink_tc_bind_pool_th_restore $swp1 1 ingress
diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh
index 093bed088ad0..373d5f2a846e 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh
@@ -234,15 +234,15 @@ __tc_sample_rate_test()
psample_capture_start
- ip vrf exec v$h1 $MZ $h1 -c 3200 -d 1msec -p 64 -A 192.0.2.1 \
+ ip vrf exec v$h1 $MZ $h1 -c 320000 -d 100usec -p 64 -A 192.0.2.1 \
-B $dip -t udp dp=52768,sp=42768 -q
psample_capture_stop
pkts=$(grep -e "group 1 " $CAPTURE_FILE | wc -l)
- pct=$((100 * (pkts - 100) / 100))
+ pct=$((100 * (pkts - 10000) / 10000))
(( -25 <= pct && pct <= 25))
- check_err $? "Expected 100 packets, got $pkts packets, which is $pct% off. Required accuracy is +-25%"
+ check_err $? "Expected 10000 packets, got $pkts packets, which is $pct% off. Required accuracy is +-25%"
log_test "tc sample rate ($desc)"
@@ -587,15 +587,15 @@ __tc_sample_acl_rate_test()
psample_capture_start
- ip vrf exec v$h1 $MZ $h1 -c 3200 -d 1msec -p 64 -A 192.0.2.1 \
+ ip vrf exec v$h1 $MZ $h1 -c 320000 -d 100usec -p 64 -A 192.0.2.1 \
-B 198.51.100.1 -t udp dp=52768,sp=42768 -q
psample_capture_stop
pkts=$(grep -e "group 1 " $CAPTURE_FILE | wc -l)
- pct=$((100 * (pkts - 100) / 100))
+ pct=$((100 * (pkts - 10000) / 10000))
(( -25 <= pct && pct <= 25))
- check_err $? "Expected 100 packets, got $pkts packets, which is $pct% off. Required accuracy is +-25%"
+ check_err $? "Expected 10000 packets, got $pkts packets, which is $pct% off. Required accuracy is +-25%"
# Setup a filter that should not match any packet and make sure packets
# are not sampled.
diff --git a/tools/testing/selftests/net/forwarding/custom_multipath_hash.sh b/tools/testing/selftests/net/forwarding/custom_multipath_hash.sh
new file mode 100755
index 000000000000..a15d21dc035a
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/custom_multipath_hash.sh
@@ -0,0 +1,364 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test traffic distribution between two paths when using custom hash policy.
+#
+# +--------------------------------+
+# | H1 |
+# | $h1 + |
+# | 198.51.100.{2-253}/24 | |
+# | 2001:db8:1::{2-fd}/64 | |
+# +-------------------------|------+
+# |
+# +-------------------------|-------------------------+
+# | SW1 | |
+# | $rp1 + |
+# | 198.51.100.1/24 |
+# | 2001:db8:1::1/64 |
+# | |
+# | |
+# | $rp11 + + $rp12 |
+# | 192.0.2.1/28 | | 192.0.2.17/28 |
+# | 2001:db8:2::1/64 | | 2001:db8:3::1/64 |
+# +------------------|-------------|------------------+
+# | |
+# +------------------|-------------|------------------+
+# | SW2 | | |
+# | | | |
+# | $rp21 + + $rp22 |
+# | 192.0.2.2/28 192.0.2.18/28 |
+# | 2001:db8:2::2/64 2001:db8:3::2/64 |
+# | |
+# | |
+# | $rp2 + |
+# | 203.0.113.1/24 | |
+# | 2001:db8:4::1/64 | |
+# +-------------------------|-------------------------+
+# |
+# +-------------------------|------+
+# | H2 | |
+# | $h2 + |
+# | 203.0.113.{2-253}/24 |
+# | 2001:db8:4::{2-fd}/64 |
+# +--------------------------------+
+
+ALL_TESTS="
+ ping_ipv4
+ ping_ipv6
+ custom_hash
+"
+
+NUM_NETIFS=8
+source lib.sh
+
+h1_create()
+{
+ simple_if_init $h1 198.51.100.2/24 2001:db8:1::2/64
+ ip route add vrf v$h1 default via 198.51.100.1 dev $h1
+ ip -6 route add vrf v$h1 default via 2001:db8:1::1 dev $h1
+}
+
+h1_destroy()
+{
+ ip -6 route del vrf v$h1 default
+ ip route del vrf v$h1 default
+ simple_if_fini $h1 198.51.100.2/24 2001:db8:1::2/64
+}
+
+sw1_create()
+{
+ simple_if_init $rp1 198.51.100.1/24 2001:db8:1::1/64
+ __simple_if_init $rp11 v$rp1 192.0.2.1/28 2001:db8:2::1/64
+ __simple_if_init $rp12 v$rp1 192.0.2.17/28 2001:db8:3::1/64
+
+ ip route add vrf v$rp1 203.0.113.0/24 \
+ nexthop via 192.0.2.2 dev $rp11 \
+ nexthop via 192.0.2.18 dev $rp12
+
+ ip -6 route add vrf v$rp1 2001:db8:4::/64 \
+ nexthop via 2001:db8:2::2 dev $rp11 \
+ nexthop via 2001:db8:3::2 dev $rp12
+}
+
+sw1_destroy()
+{
+ ip -6 route del vrf v$rp1 2001:db8:4::/64
+
+ ip route del vrf v$rp1 203.0.113.0/24
+
+ __simple_if_fini $rp12 192.0.2.17/28 2001:db8:3::1/64
+ __simple_if_fini $rp11 192.0.2.1/28 2001:db8:2::1/64
+ simple_if_fini $rp1 198.51.100.1/24 2001:db8:1::1/64
+}
+
+sw2_create()
+{
+ simple_if_init $rp2 203.0.113.1/24 2001:db8:4::1/64
+ __simple_if_init $rp21 v$rp2 192.0.2.2/28 2001:db8:2::2/64
+ __simple_if_init $rp22 v$rp2 192.0.2.18/28 2001:db8:3::2/64
+
+ ip route add vrf v$rp2 198.51.100.0/24 \
+ nexthop via 192.0.2.1 dev $rp21 \
+ nexthop via 192.0.2.17 dev $rp22
+
+ ip -6 route add vrf v$rp2 2001:db8:1::/64 \
+ nexthop via 2001:db8:2::1 dev $rp21 \
+ nexthop via 2001:db8:3::1 dev $rp22
+}
+
+sw2_destroy()
+{
+ ip -6 route del vrf v$rp2 2001:db8:1::/64
+
+ ip route del vrf v$rp2 198.51.100.0/24
+
+ __simple_if_fini $rp22 192.0.2.18/28 2001:db8:3::2/64
+ __simple_if_fini $rp21 192.0.2.2/28 2001:db8:2::2/64
+ simple_if_fini $rp2 203.0.113.1/24 2001:db8:4::1/64
+}
+
+h2_create()
+{
+ simple_if_init $h2 203.0.113.2/24 2001:db8:4::2/64
+ ip route add vrf v$h2 default via 203.0.113.1 dev $h2
+ ip -6 route add vrf v$h2 default via 2001:db8:4::1 dev $h2
+}
+
+h2_destroy()
+{
+ ip -6 route del vrf v$h2 default
+ ip route del vrf v$h2 default
+ simple_if_fini $h2 203.0.113.2/24 2001:db8:4::2/64
+}
+
+setup_prepare()
+{
+ h1=${NETIFS[p1]}
+
+ rp1=${NETIFS[p2]}
+
+ rp11=${NETIFS[p3]}
+ rp21=${NETIFS[p4]}
+
+ rp12=${NETIFS[p5]}
+ rp22=${NETIFS[p6]}
+
+ rp2=${NETIFS[p7]}
+
+ h2=${NETIFS[p8]}
+
+ vrf_prepare
+ h1_create
+ sw1_create
+ sw2_create
+ h2_create
+
+ forwarding_enable
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ forwarding_restore
+
+ h2_destroy
+ sw2_destroy
+ sw1_destroy
+ h1_destroy
+ vrf_cleanup
+}
+
+ping_ipv4()
+{
+ ping_test $h1 203.0.113.2
+}
+
+ping_ipv6()
+{
+ ping6_test $h1 2001:db8:4::2
+}
+
+send_src_ipv4()
+{
+ $MZ $h1 -q -p 64 -A "198.51.100.2-198.51.100.253" -B 203.0.113.2 \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_dst_ipv4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B "203.0.113.2-203.0.113.253" \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_src_udp4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B 203.0.113.2 \
+ -d 1msec -t udp "sp=0-32768,dp=30000"
+}
+
+send_dst_udp4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B 203.0.113.2 \
+ -d 1msec -t udp "sp=20000,dp=0-32768"
+}
+
+send_src_ipv6()
+{
+ $MZ -6 $h1 -q -p 64 -A "2001:db8:1::2-2001:db8:1::fd" -B 2001:db8:4::2 \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_dst_ipv6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B "2001:db8:4::2-2001:db8:4::fd" \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_flowlabel()
+{
+ # Generate 16384 echo requests, each with a random flow label.
+ for _ in $(seq 1 16384); do
+ ip vrf exec v$h1 \
+ $PING6 2001:db8:4::2 -F 0 -c 1 -q >/dev/null 2>&1
+ done
+}
+
+send_src_udp6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:4::2 \
+ -d 1msec -t udp "sp=0-32768,dp=30000"
+}
+
+send_dst_udp6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:4::2 \
+ -d 1msec -t udp "sp=20000,dp=0-32768"
+}
+
+custom_hash_test()
+{
+ local field="$1"; shift
+ local balanced="$1"; shift
+ local send_flows="$@"
+
+ RET=0
+
+ local t0_rp11=$(link_stats_tx_packets_get $rp11)
+ local t0_rp12=$(link_stats_tx_packets_get $rp12)
+
+ $send_flows
+
+ local t1_rp11=$(link_stats_tx_packets_get $rp11)
+ local t1_rp12=$(link_stats_tx_packets_get $rp12)
+
+ local d_rp11=$((t1_rp11 - t0_rp11))
+ local d_rp12=$((t1_rp12 - t0_rp12))
+
+ local diff=$((d_rp12 - d_rp11))
+ local sum=$((d_rp11 + d_rp12))
+
+ local pct=$(echo "$diff / $sum * 100" | bc -l)
+ local is_balanced=$(echo "-20 <= $pct && $pct <= 20" | bc)
+
+ [[ ( $is_balanced -eq 1 && $balanced == "balanced" ) ||
+ ( $is_balanced -eq 0 && $balanced == "unbalanced" ) ]]
+ check_err $? "Expected traffic to be $balanced, but it is not"
+
+ log_test "Multipath hash field: $field ($balanced)"
+ log_info "Packets sent on path1 / path2: $d_rp11 / $d_rp12"
+}
+
+custom_hash_v4()
+{
+ log_info "Running IPv4 custom multipath hash tests"
+
+ sysctl_set net.ipv4.fib_multipath_hash_policy 3
+
+ # Prevent the neighbour table from overflowing, as different neighbour
+ # entries will be created on $ol4 when using different destination IPs.
+ sysctl_set net.ipv4.neigh.default.gc_thresh1 1024
+ sysctl_set net.ipv4.neigh.default.gc_thresh2 1024
+ sysctl_set net.ipv4.neigh.default.gc_thresh3 1024
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0001
+ custom_hash_test "Source IP" "balanced" send_src_ipv4
+ custom_hash_test "Source IP" "unbalanced" send_dst_ipv4
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0002
+ custom_hash_test "Destination IP" "balanced" send_dst_ipv4
+ custom_hash_test "Destination IP" "unbalanced" send_src_ipv4
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0010
+ custom_hash_test "Source port" "balanced" send_src_udp4
+ custom_hash_test "Source port" "unbalanced" send_dst_udp4
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0020
+ custom_hash_test "Destination port" "balanced" send_dst_udp4
+ custom_hash_test "Destination port" "unbalanced" send_src_udp4
+
+ sysctl_restore net.ipv4.neigh.default.gc_thresh3
+ sysctl_restore net.ipv4.neigh.default.gc_thresh2
+ sysctl_restore net.ipv4.neigh.default.gc_thresh1
+
+ sysctl_restore net.ipv4.fib_multipath_hash_policy
+}
+
+custom_hash_v6()
+{
+ log_info "Running IPv6 custom multipath hash tests"
+
+ sysctl_set net.ipv6.fib_multipath_hash_policy 3
+
+ # Prevent the neighbour table from overflowing, as different neighbour
+ # entries will be created on $ol4 when using different destination IPs.
+ sysctl_set net.ipv6.neigh.default.gc_thresh1 1024
+ sysctl_set net.ipv6.neigh.default.gc_thresh2 1024
+ sysctl_set net.ipv6.neigh.default.gc_thresh3 1024
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0001
+ custom_hash_test "Source IP" "balanced" send_src_ipv6
+ custom_hash_test "Source IP" "unbalanced" send_dst_ipv6
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0002
+ custom_hash_test "Destination IP" "balanced" send_dst_ipv6
+ custom_hash_test "Destination IP" "unbalanced" send_src_ipv6
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0008
+ custom_hash_test "Flowlabel" "balanced" send_flowlabel
+ custom_hash_test "Flowlabel" "unbalanced" send_src_ipv6
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0010
+ custom_hash_test "Source port" "balanced" send_src_udp6
+ custom_hash_test "Source port" "unbalanced" send_dst_udp6
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0020
+ custom_hash_test "Destination port" "balanced" send_dst_udp6
+ custom_hash_test "Destination port" "unbalanced" send_src_udp6
+
+ sysctl_restore net.ipv6.neigh.default.gc_thresh3
+ sysctl_restore net.ipv6.neigh.default.gc_thresh2
+ sysctl_restore net.ipv6.neigh.default.gc_thresh1
+
+ sysctl_restore net.ipv6.fib_multipath_hash_policy
+}
+
+custom_hash()
+{
+ # Test that when the hash policy is set to custom, traffic is
+ # distributed only according to the fields set in the
+ # fib_multipath_hash_fields sysctl.
+ #
+ # Each time set a different field and make sure traffic is only
+ # distributed when the field is changed in the packet stream.
+ custom_hash_v4
+ custom_hash_v6
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+tests_run
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/gre_custom_multipath_hash.sh b/tools/testing/selftests/net/forwarding/gre_custom_multipath_hash.sh
new file mode 100755
index 000000000000..a73f52efcb6c
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/gre_custom_multipath_hash.sh
@@ -0,0 +1,456 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test traffic distribution when there are multiple paths between an IPv4 GRE
+# tunnel. The tunnel carries IPv4 and IPv6 traffic between multiple hosts.
+# Multiple routes are in the underlay network. With the default multipath
+# policy, SW2 will only look at the outer IP addresses, hence only a single
+# route would be used.
+#
+# +--------------------------------+
+# | H1 |
+# | $h1 + |
+# | 198.51.100.{2-253}/24 | |
+# | 2001:db8:1::{2-fd}/64 | |
+# +-------------------------|------+
+# |
+# +-------------------------|------------------+
+# | SW1 | |
+# | $ol1 + |
+# | 198.51.100.1/24 |
+# | 2001:db8:1::1/64 |
+# | |
+# | + g1 (gre) |
+# | loc=192.0.2.1 |
+# | rem=192.0.2.2 --. |
+# | tos=inherit | |
+# | v |
+# | + $ul1 |
+# | | 192.0.2.17/28 |
+# +---------------------|----------------------+
+# |
+# +---------------------|----------------------+
+# | SW2 | |
+# | $ul21 + |
+# | 192.0.2.18/28 | |
+# | | |
+# ! __________________+___ |
+# | / \ |
+# | | | |
+# | + $ul22.111 (vlan) + $ul22.222 (vlan) |
+# | | 192.0.2.33/28 | 192.0.2.49/28 |
+# | | | |
+# +--|----------------------|------------------+
+# | |
+# +--|----------------------|------------------+
+# | | | |
+# | + $ul32.111 (vlan) + $ul32.222 (vlan) |
+# | | 192.0.2.34/28 | 192.0.2.50/28 |
+# | | | |
+# | \__________________+___/ |
+# | | |
+# | | |
+# | $ul31 + |
+# | 192.0.2.65/28 | SW3 |
+# +---------------------|----------------------+
+# |
+# +---------------------|----------------------+
+# | + $ul4 |
+# | ^ 192.0.2.66/28 |
+# | | |
+# | + g2 (gre) | |
+# | loc=192.0.2.2 | |
+# | rem=192.0.2.1 --' |
+# | tos=inherit |
+# | |
+# | $ol4 + |
+# | 203.0.113.1/24 | |
+# | 2001:db8:2::1/64 | SW4 |
+# +-------------------------|------------------+
+# |
+# +-------------------------|------+
+# | | |
+# | $h2 + |
+# | 203.0.113.{2-253}/24 |
+# | 2001:db8:2::{2-fd}/64 H2 |
+# +--------------------------------+
+
+ALL_TESTS="
+ ping_ipv4
+ ping_ipv6
+ custom_hash
+"
+
+NUM_NETIFS=10
+source lib.sh
+
+h1_create()
+{
+ simple_if_init $h1 198.51.100.2/24 2001:db8:1::2/64
+ ip route add vrf v$h1 default via 198.51.100.1 dev $h1
+ ip -6 route add vrf v$h1 default via 2001:db8:1::1 dev $h1
+}
+
+h1_destroy()
+{
+ ip -6 route del vrf v$h1 default
+ ip route del vrf v$h1 default
+ simple_if_fini $h1 198.51.100.2/24 2001:db8:1::2/64
+}
+
+sw1_create()
+{
+ simple_if_init $ol1 198.51.100.1/24 2001:db8:1::1/64
+ __simple_if_init $ul1 v$ol1 192.0.2.17/28
+
+ tunnel_create g1 gre 192.0.2.1 192.0.2.2 tos inherit dev v$ol1
+ __simple_if_init g1 v$ol1 192.0.2.1/32
+ ip route add vrf v$ol1 192.0.2.2/32 via 192.0.2.18
+
+ ip route add vrf v$ol1 203.0.113.0/24 dev g1
+ ip -6 route add vrf v$ol1 2001:db8:2::/64 dev g1
+}
+
+sw1_destroy()
+{
+ ip -6 route del vrf v$ol1 2001:db8:2::/64
+ ip route del vrf v$ol1 203.0.113.0/24
+
+ ip route del vrf v$ol1 192.0.2.2/32
+ __simple_if_fini g1 192.0.2.1/32
+ tunnel_destroy g1
+
+ __simple_if_fini $ul1 192.0.2.17/28
+ simple_if_fini $ol1 198.51.100.1/24 2001:db8:1::1/64
+}
+
+sw2_create()
+{
+ simple_if_init $ul21 192.0.2.18/28
+ __simple_if_init $ul22 v$ul21
+ vlan_create $ul22 111 v$ul21 192.0.2.33/28
+ vlan_create $ul22 222 v$ul21 192.0.2.49/28
+
+ ip route add vrf v$ul21 192.0.2.1/32 via 192.0.2.17
+ ip route add vrf v$ul21 192.0.2.2/32 \
+ nexthop via 192.0.2.34 \
+ nexthop via 192.0.2.50
+}
+
+sw2_destroy()
+{
+ ip route del vrf v$ul21 192.0.2.2/32
+ ip route del vrf v$ul21 192.0.2.1/32
+
+ vlan_destroy $ul22 222
+ vlan_destroy $ul22 111
+ __simple_if_fini $ul22
+ simple_if_fini $ul21 192.0.2.18/28
+}
+
+sw3_create()
+{
+ simple_if_init $ul31 192.0.2.65/28
+ __simple_if_init $ul32 v$ul31
+ vlan_create $ul32 111 v$ul31 192.0.2.34/28
+ vlan_create $ul32 222 v$ul31 192.0.2.50/28
+
+ ip route add vrf v$ul31 192.0.2.2/32 via 192.0.2.66
+ ip route add vrf v$ul31 192.0.2.1/32 \
+ nexthop via 192.0.2.33 \
+ nexthop via 192.0.2.49
+
+ tc qdisc add dev $ul32 clsact
+ tc filter add dev $ul32 ingress pref 111 prot 802.1Q \
+ flower vlan_id 111 action pass
+ tc filter add dev $ul32 ingress pref 222 prot 802.1Q \
+ flower vlan_id 222 action pass
+}
+
+sw3_destroy()
+{
+ tc qdisc del dev $ul32 clsact
+
+ ip route del vrf v$ul31 192.0.2.1/32
+ ip route del vrf v$ul31 192.0.2.2/32
+
+ vlan_destroy $ul32 222
+ vlan_destroy $ul32 111
+ __simple_if_fini $ul32
+ simple_if_fini $ul31 192.0.2.65/28
+}
+
+sw4_create()
+{
+ simple_if_init $ol4 203.0.113.1/24 2001:db8:2::1/64
+ __simple_if_init $ul4 v$ol4 192.0.2.66/28
+
+ tunnel_create g2 gre 192.0.2.2 192.0.2.1 tos inherit dev v$ol4
+ __simple_if_init g2 v$ol4 192.0.2.2/32
+ ip route add vrf v$ol4 192.0.2.1/32 via 192.0.2.65
+
+ ip route add vrf v$ol4 198.51.100.0/24 dev g2
+ ip -6 route add vrf v$ol4 2001:db8:1::/64 dev g2
+}
+
+sw4_destroy()
+{
+ ip -6 route del vrf v$ol4 2001:db8:1::/64
+ ip route del vrf v$ol4 198.51.100.0/24
+
+ ip route del vrf v$ol4 192.0.2.1/32
+ __simple_if_fini g2 192.0.2.2/32
+ tunnel_destroy g2
+
+ __simple_if_fini $ul4 192.0.2.66/28
+ simple_if_fini $ol4 203.0.113.1/24 2001:db8:2::1/64
+}
+
+h2_create()
+{
+ simple_if_init $h2 203.0.113.2/24 2001:db8:2::2/64
+ ip route add vrf v$h2 default via 203.0.113.1 dev $h2
+ ip -6 route add vrf v$h2 default via 2001:db8:2::1 dev $h2
+}
+
+h2_destroy()
+{
+ ip -6 route del vrf v$h2 default
+ ip route del vrf v$h2 default
+ simple_if_fini $h2 203.0.113.2/24 2001:db8:2::2/64
+}
+
+setup_prepare()
+{
+ h1=${NETIFS[p1]}
+
+ ol1=${NETIFS[p2]}
+ ul1=${NETIFS[p3]}
+
+ ul21=${NETIFS[p4]}
+ ul22=${NETIFS[p5]}
+
+ ul32=${NETIFS[p6]}
+ ul31=${NETIFS[p7]}
+
+ ul4=${NETIFS[p8]}
+ ol4=${NETIFS[p9]}
+
+ h2=${NETIFS[p10]}
+
+ vrf_prepare
+ h1_create
+ sw1_create
+ sw2_create
+ sw3_create
+ sw4_create
+ h2_create
+
+ forwarding_enable
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ forwarding_restore
+
+ h2_destroy
+ sw4_destroy
+ sw3_destroy
+ sw2_destroy
+ sw1_destroy
+ h1_destroy
+ vrf_cleanup
+}
+
+ping_ipv4()
+{
+ ping_test $h1 203.0.113.2
+}
+
+ping_ipv6()
+{
+ ping6_test $h1 2001:db8:2::2
+}
+
+send_src_ipv4()
+{
+ $MZ $h1 -q -p 64 -A "198.51.100.2-198.51.100.253" -B 203.0.113.2 \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_dst_ipv4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B "203.0.113.2-203.0.113.253" \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_src_udp4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B 203.0.113.2 \
+ -d 1msec -t udp "sp=0-32768,dp=30000"
+}
+
+send_dst_udp4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B 203.0.113.2 \
+ -d 1msec -t udp "sp=20000,dp=0-32768"
+}
+
+send_src_ipv6()
+{
+ $MZ -6 $h1 -q -p 64 -A "2001:db8:1::2-2001:db8:1::fd" -B 2001:db8:2::2 \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_dst_ipv6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B "2001:db8:2::2-2001:db8:2::fd" \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_flowlabel()
+{
+ # Generate 16384 echo requests, each with a random flow label.
+ for _ in $(seq 1 16384); do
+ ip vrf exec v$h1 \
+ $PING6 2001:db8:2::2 -F 0 -c 1 -q >/dev/null 2>&1
+ done
+}
+
+send_src_udp6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \
+ -d 1msec -t udp "sp=0-32768,dp=30000"
+}
+
+send_dst_udp6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \
+ -d 1msec -t udp "sp=20000,dp=0-32768"
+}
+
+custom_hash_test()
+{
+ local field="$1"; shift
+ local balanced="$1"; shift
+ local send_flows="$@"
+
+ RET=0
+
+ local t0_111=$(tc_rule_stats_get $ul32 111 ingress)
+ local t0_222=$(tc_rule_stats_get $ul32 222 ingress)
+
+ $send_flows
+
+ local t1_111=$(tc_rule_stats_get $ul32 111 ingress)
+ local t1_222=$(tc_rule_stats_get $ul32 222 ingress)
+
+ local d111=$((t1_111 - t0_111))
+ local d222=$((t1_222 - t0_222))
+
+ local diff=$((d222 - d111))
+ local sum=$((d111 + d222))
+
+ local pct=$(echo "$diff / $sum * 100" | bc -l)
+ local is_balanced=$(echo "-20 <= $pct && $pct <= 20" | bc)
+
+ [[ ( $is_balanced -eq 1 && $balanced == "balanced" ) ||
+ ( $is_balanced -eq 0 && $balanced == "unbalanced" ) ]]
+ check_err $? "Expected traffic to be $balanced, but it is not"
+
+ log_test "Multipath hash field: $field ($balanced)"
+ log_info "Packets sent on path1 / path2: $d111 / $d222"
+}
+
+custom_hash_v4()
+{
+ log_info "Running IPv4 overlay custom multipath hash tests"
+
+ # Prevent the neighbour table from overflowing, as different neighbour
+ # entries will be created on $ol4 when using different destination IPs.
+ sysctl_set net.ipv4.neigh.default.gc_thresh1 1024
+ sysctl_set net.ipv4.neigh.default.gc_thresh2 1024
+ sysctl_set net.ipv4.neigh.default.gc_thresh3 1024
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0040
+ custom_hash_test "Inner source IP" "balanced" send_src_ipv4
+ custom_hash_test "Inner source IP" "unbalanced" send_dst_ipv4
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0080
+ custom_hash_test "Inner destination IP" "balanced" send_dst_ipv4
+ custom_hash_test "Inner destination IP" "unbalanced" send_src_ipv4
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0400
+ custom_hash_test "Inner source port" "balanced" send_src_udp4
+ custom_hash_test "Inner source port" "unbalanced" send_dst_udp4
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0800
+ custom_hash_test "Inner destination port" "balanced" send_dst_udp4
+ custom_hash_test "Inner destination port" "unbalanced" send_src_udp4
+
+ sysctl_restore net.ipv4.neigh.default.gc_thresh3
+ sysctl_restore net.ipv4.neigh.default.gc_thresh2
+ sysctl_restore net.ipv4.neigh.default.gc_thresh1
+}
+
+custom_hash_v6()
+{
+ log_info "Running IPv6 overlay custom multipath hash tests"
+
+ # Prevent the neighbour table from overflowing, as different neighbour
+ # entries will be created on $ol4 when using different destination IPs.
+ sysctl_set net.ipv6.neigh.default.gc_thresh1 1024
+ sysctl_set net.ipv6.neigh.default.gc_thresh2 1024
+ sysctl_set net.ipv6.neigh.default.gc_thresh3 1024
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0040
+ custom_hash_test "Inner source IP" "balanced" send_src_ipv6
+ custom_hash_test "Inner source IP" "unbalanced" send_dst_ipv6
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0080
+ custom_hash_test "Inner destination IP" "balanced" send_dst_ipv6
+ custom_hash_test "Inner destination IP" "unbalanced" send_src_ipv6
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0200
+ custom_hash_test "Inner flowlabel" "balanced" send_flowlabel
+ custom_hash_test "Inner flowlabel" "unbalanced" send_src_ipv6
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0400
+ custom_hash_test "Inner source port" "balanced" send_src_udp6
+ custom_hash_test "Inner source port" "unbalanced" send_dst_udp6
+
+ sysctl_set net.ipv4.fib_multipath_hash_fields 0x0800
+ custom_hash_test "Inner destination port" "balanced" send_dst_udp6
+ custom_hash_test "Inner destination port" "unbalanced" send_src_udp6
+
+ sysctl_restore net.ipv6.neigh.default.gc_thresh3
+ sysctl_restore net.ipv6.neigh.default.gc_thresh2
+ sysctl_restore net.ipv6.neigh.default.gc_thresh1
+}
+
+custom_hash()
+{
+ # Test that when the hash policy is set to custom, traffic is
+ # distributed only according to the fields set in the
+ # fib_multipath_hash_fields sysctl.
+ #
+ # Each time set a different field and make sure traffic is only
+ # distributed when the field is changed in the packet stream.
+
+ sysctl_set net.ipv4.fib_multipath_hash_policy 3
+
+ custom_hash_v4
+ custom_hash_v6
+
+ sysctl_restore net.ipv4.fib_multipath_hash_policy
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+tests_run
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/ip6gre_custom_multipath_hash.sh b/tools/testing/selftests/net/forwarding/ip6gre_custom_multipath_hash.sh
new file mode 100755
index 000000000000..8fea2c2e0b25
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/ip6gre_custom_multipath_hash.sh
@@ -0,0 +1,458 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test traffic distribution when there are multiple paths between an IPv6 GRE
+# tunnel. The tunnel carries IPv4 and IPv6 traffic between multiple hosts.
+# Multiple routes are in the underlay network. With the default multipath
+# policy, SW2 will only look at the outer IP addresses, hence only a single
+# route would be used.
+#
+# +--------------------------------+
+# | H1 |
+# | $h1 + |
+# | 198.51.100.{2-253}/24 | |
+# | 2001:db8:1::{2-fd}/64 | |
+# +-------------------------|------+
+# |
+# +-------------------------|-------------------+
+# | SW1 | |
+# | $ol1 + |
+# | 198.51.100.1/24 |
+# | 2001:db8:1::1/64 |
+# | |
+# |+ g1 (ip6gre) |
+# | loc=2001:db8:3::1 |
+# | rem=2001:db8:3::2 -. |
+# | tos=inherit | |
+# | v |
+# | + $ul1 |
+# | | 2001:db8:10::1/64 |
+# +---------------------|-----------------------+
+# |
+# +---------------------|-----------------------+
+# | SW2 | |
+# | $ul21 + |
+# | 2001:db8:10::2/64 | |
+# | | |
+# ! __________________+___ |
+# | / \ |
+# | | | |
+# | + $ul22.111 (vlan) + $ul22.222 (vlan) |
+# | | 2001:db8:11::1/64 | 2001:db8:12::1/64 |
+# | | | |
+# +--|----------------------|-------------------+
+# | |
+# +--|----------------------|-------------------+
+# | | | |
+# | + $ul32.111 (vlan) + $ul32.222 (vlan) |
+# | | 2001:db8:11::2/64 | 2001:db8:12::2/64 |
+# | | | |
+# | \__________________+___/ |
+# | | |
+# | | |
+# | $ul31 + |
+# | 2001:db8:13::1/64 | SW3 |
+# +---------------------|-----------------------+
+# |
+# +---------------------|-----------------------+
+# | + $ul4 |
+# | ^ 2001:db8:13::2/64 |
+# | | |
+# |+ g2 (ip6gre) | |
+# | loc=2001:db8:3::2 | |
+# | rem=2001:db8:3::1 -' |
+# | tos=inherit |
+# | |
+# | $ol4 + |
+# | 203.0.113.1/24 | |
+# | 2001:db8:2::1/64 | SW4 |
+# +-------------------------|-------------------+
+# |
+# +-------------------------|------+
+# | | |
+# | $h2 + |
+# | 203.0.113.{2-253}/24 |
+# | 2001:db8:2::{2-fd}/64 H2 |
+# +--------------------------------+
+
+ALL_TESTS="
+ ping_ipv4
+ ping_ipv6
+ custom_hash
+"
+
+NUM_NETIFS=10
+source lib.sh
+
+h1_create()
+{
+ simple_if_init $h1 198.51.100.2/24 2001:db8:1::2/64
+ ip route add vrf v$h1 default via 198.51.100.1 dev $h1
+ ip -6 route add vrf v$h1 default via 2001:db8:1::1 dev $h1
+}
+
+h1_destroy()
+{
+ ip -6 route del vrf v$h1 default
+ ip route del vrf v$h1 default
+ simple_if_fini $h1 198.51.100.2/24 2001:db8:1::2/64
+}
+
+sw1_create()
+{
+ simple_if_init $ol1 198.51.100.1/24 2001:db8:1::1/64
+ __simple_if_init $ul1 v$ol1 2001:db8:10::1/64
+
+ tunnel_create g1 ip6gre 2001:db8:3::1 2001:db8:3::2 tos inherit \
+ dev v$ol1
+ __simple_if_init g1 v$ol1 2001:db8:3::1/128
+ ip route add vrf v$ol1 2001:db8:3::2/128 via 2001:db8:10::2
+
+ ip route add vrf v$ol1 203.0.113.0/24 dev g1
+ ip -6 route add vrf v$ol1 2001:db8:2::/64 dev g1
+}
+
+sw1_destroy()
+{
+ ip -6 route del vrf v$ol1 2001:db8:2::/64
+ ip route del vrf v$ol1 203.0.113.0/24
+
+ ip route del vrf v$ol1 2001:db8:3::2/128
+ __simple_if_fini g1 2001:db8:3::1/128
+ tunnel_destroy g1
+
+ __simple_if_fini $ul1 2001:db8:10::1/64
+ simple_if_fini $ol1 198.51.100.1/24 2001:db8:1::1/64
+}
+
+sw2_create()
+{
+ simple_if_init $ul21 2001:db8:10::2/64
+ __simple_if_init $ul22 v$ul21
+ vlan_create $ul22 111 v$ul21 2001:db8:11::1/64
+ vlan_create $ul22 222 v$ul21 2001:db8:12::1/64
+
+ ip -6 route add vrf v$ul21 2001:db8:3::1/128 via 2001:db8:10::1
+ ip -6 route add vrf v$ul21 2001:db8:3::2/128 \
+ nexthop via 2001:db8:11::2 \
+ nexthop via 2001:db8:12::2
+}
+
+sw2_destroy()
+{
+ ip -6 route del vrf v$ul21 2001:db8:3::2/128
+ ip -6 route del vrf v$ul21 2001:db8:3::1/128
+
+ vlan_destroy $ul22 222
+ vlan_destroy $ul22 111
+ __simple_if_fini $ul22
+ simple_if_fini $ul21 2001:db8:10::2/64
+}
+
+sw3_create()
+{
+ simple_if_init $ul31 2001:db8:13::1/64
+ __simple_if_init $ul32 v$ul31
+ vlan_create $ul32 111 v$ul31 2001:db8:11::2/64
+ vlan_create $ul32 222 v$ul31 2001:db8:12::2/64
+
+ ip -6 route add vrf v$ul31 2001:db8:3::2/128 via 2001:db8:13::2
+ ip -6 route add vrf v$ul31 2001:db8:3::1/128 \
+ nexthop via 2001:db8:11::1 \
+ nexthop via 2001:db8:12::1
+
+ tc qdisc add dev $ul32 clsact
+ tc filter add dev $ul32 ingress pref 111 prot 802.1Q \
+ flower vlan_id 111 action pass
+ tc filter add dev $ul32 ingress pref 222 prot 802.1Q \
+ flower vlan_id 222 action pass
+}
+
+sw3_destroy()
+{
+ tc qdisc del dev $ul32 clsact
+
+ ip -6 route del vrf v$ul31 2001:db8:3::1/128
+ ip -6 route del vrf v$ul31 2001:db8:3::2/128
+
+ vlan_destroy $ul32 222
+ vlan_destroy $ul32 111
+ __simple_if_fini $ul32
+ simple_if_fini $ul31 2001:db8:13::1/64
+}
+
+sw4_create()
+{
+ simple_if_init $ol4 203.0.113.1/24 2001:db8:2::1/64
+ __simple_if_init $ul4 v$ol4 2001:db8:13::2/64
+
+ tunnel_create g2 ip6gre 2001:db8:3::2 2001:db8:3::1 tos inherit \
+ dev v$ol4
+ __simple_if_init g2 v$ol4 2001:db8:3::2/128
+ ip -6 route add vrf v$ol4 2001:db8:3::1/128 via 2001:db8:13::1
+
+ ip route add vrf v$ol4 198.51.100.0/24 dev g2
+ ip -6 route add vrf v$ol4 2001:db8:1::/64 dev g2
+}
+
+sw4_destroy()
+{
+ ip -6 route del vrf v$ol4 2001:db8:1::/64
+ ip route del vrf v$ol4 198.51.100.0/24
+
+ ip -6 route del vrf v$ol4 2001:db8:3::1/128
+ __simple_if_fini g2 2001:db8:3::2/128
+ tunnel_destroy g2
+
+ __simple_if_fini $ul4 2001:db8:13::2/64
+ simple_if_fini $ol4 203.0.113.1/24 2001:db8:2::1/64
+}
+
+h2_create()
+{
+ simple_if_init $h2 203.0.113.2/24 2001:db8:2::2/64
+ ip route add vrf v$h2 default via 203.0.113.1 dev $h2
+ ip -6 route add vrf v$h2 default via 2001:db8:2::1 dev $h2
+}
+
+h2_destroy()
+{
+ ip -6 route del vrf v$h2 default
+ ip route del vrf v$h2 default
+ simple_if_fini $h2 203.0.113.2/24 2001:db8:2::2/64
+}
+
+setup_prepare()
+{
+ h1=${NETIFS[p1]}
+
+ ol1=${NETIFS[p2]}
+ ul1=${NETIFS[p3]}
+
+ ul21=${NETIFS[p4]}
+ ul22=${NETIFS[p5]}
+
+ ul32=${NETIFS[p6]}
+ ul31=${NETIFS[p7]}
+
+ ul4=${NETIFS[p8]}
+ ol4=${NETIFS[p9]}
+
+ h2=${NETIFS[p10]}
+
+ vrf_prepare
+ h1_create
+ sw1_create
+ sw2_create
+ sw3_create
+ sw4_create
+ h2_create
+
+ forwarding_enable
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ forwarding_restore
+
+ h2_destroy
+ sw4_destroy
+ sw3_destroy
+ sw2_destroy
+ sw1_destroy
+ h1_destroy
+ vrf_cleanup
+}
+
+ping_ipv4()
+{
+ ping_test $h1 203.0.113.2
+}
+
+ping_ipv6()
+{
+ ping6_test $h1 2001:db8:2::2
+}
+
+send_src_ipv4()
+{
+ $MZ $h1 -q -p 64 -A "198.51.100.2-198.51.100.253" -B 203.0.113.2 \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_dst_ipv4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B "203.0.113.2-203.0.113.253" \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_src_udp4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B 203.0.113.2 \
+ -d 1msec -t udp "sp=0-32768,dp=30000"
+}
+
+send_dst_udp4()
+{
+ $MZ $h1 -q -p 64 -A 198.51.100.2 -B 203.0.113.2 \
+ -d 1msec -t udp "sp=20000,dp=0-32768"
+}
+
+send_src_ipv6()
+{
+ $MZ -6 $h1 -q -p 64 -A "2001:db8:1::2-2001:db8:1::fd" -B 2001:db8:2::2 \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_dst_ipv6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B "2001:db8:2::2-2001:db8:2::fd" \
+ -d 1msec -c 50 -t udp "sp=20000,dp=30000"
+}
+
+send_flowlabel()
+{
+ # Generate 16384 echo requests, each with a random flow label.
+ for _ in $(seq 1 16384); do
+ ip vrf exec v$h1 \
+ $PING6 2001:db8:2::2 -F 0 -c 1 -q >/dev/null 2>&1
+ done
+}
+
+send_src_udp6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \
+ -d 1msec -t udp "sp=0-32768,dp=30000"
+}
+
+send_dst_udp6()
+{
+ $MZ -6 $h1 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \
+ -d 1msec -t udp "sp=20000,dp=0-32768"
+}
+
+custom_hash_test()
+{
+ local field="$1"; shift
+ local balanced="$1"; shift
+ local send_flows="$@"
+
+ RET=0
+
+ local t0_111=$(tc_rule_stats_get $ul32 111 ingress)
+ local t0_222=$(tc_rule_stats_get $ul32 222 ingress)
+
+ $send_flows
+
+ local t1_111=$(tc_rule_stats_get $ul32 111 ingress)
+ local t1_222=$(tc_rule_stats_get $ul32 222 ingress)
+
+ local d111=$((t1_111 - t0_111))
+ local d222=$((t1_222 - t0_222))
+
+ local diff=$((d222 - d111))
+ local sum=$((d111 + d222))
+
+ local pct=$(echo "$diff / $sum * 100" | bc -l)
+ local is_balanced=$(echo "-20 <= $pct && $pct <= 20" | bc)
+
+ [[ ( $is_balanced -eq 1 && $balanced == "balanced" ) ||
+ ( $is_balanced -eq 0 && $balanced == "unbalanced" ) ]]
+ check_err $? "Expected traffic to be $balanced, but it is not"
+
+ log_test "Multipath hash field: $field ($balanced)"
+ log_info "Packets sent on path1 / path2: $d111 / $d222"
+}
+
+custom_hash_v4()
+{
+ log_info "Running IPv4 overlay custom multipath hash tests"
+
+ # Prevent the neighbour table from overflowing, as different neighbour
+ # entries will be created on $ol4 when using different destination IPs.
+ sysctl_set net.ipv4.neigh.default.gc_thresh1 1024
+ sysctl_set net.ipv4.neigh.default.gc_thresh2 1024
+ sysctl_set net.ipv4.neigh.default.gc_thresh3 1024
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0040
+ custom_hash_test "Inner source IP" "balanced" send_src_ipv4
+ custom_hash_test "Inner source IP" "unbalanced" send_dst_ipv4
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0080
+ custom_hash_test "Inner destination IP" "balanced" send_dst_ipv4
+ custom_hash_test "Inner destination IP" "unbalanced" send_src_ipv4
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0400
+ custom_hash_test "Inner source port" "balanced" send_src_udp4
+ custom_hash_test "Inner source port" "unbalanced" send_dst_udp4
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0800
+ custom_hash_test "Inner destination port" "balanced" send_dst_udp4
+ custom_hash_test "Inner destination port" "unbalanced" send_src_udp4
+
+ sysctl_restore net.ipv4.neigh.default.gc_thresh3
+ sysctl_restore net.ipv4.neigh.default.gc_thresh2
+ sysctl_restore net.ipv4.neigh.default.gc_thresh1
+}
+
+custom_hash_v6()
+{
+ log_info "Running IPv6 overlay custom multipath hash tests"
+
+ # Prevent the neighbour table from overflowing, as different neighbour
+ # entries will be created on $ol4 when using different destination IPs.
+ sysctl_set net.ipv6.neigh.default.gc_thresh1 1024
+ sysctl_set net.ipv6.neigh.default.gc_thresh2 1024
+ sysctl_set net.ipv6.neigh.default.gc_thresh3 1024
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0040
+ custom_hash_test "Inner source IP" "balanced" send_src_ipv6
+ custom_hash_test "Inner source IP" "unbalanced" send_dst_ipv6
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0080
+ custom_hash_test "Inner destination IP" "balanced" send_dst_ipv6
+ custom_hash_test "Inner destination IP" "unbalanced" send_src_ipv6
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0200
+ custom_hash_test "Inner flowlabel" "balanced" send_flowlabel
+ custom_hash_test "Inner flowlabel" "unbalanced" send_src_ipv6
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0400
+ custom_hash_test "Inner source port" "balanced" send_src_udp6
+ custom_hash_test "Inner source port" "unbalanced" send_dst_udp6
+
+ sysctl_set net.ipv6.fib_multipath_hash_fields 0x0800
+ custom_hash_test "Inner destination port" "balanced" send_dst_udp6
+ custom_hash_test "Inner destination port" "unbalanced" send_src_udp6
+
+ sysctl_restore net.ipv6.neigh.default.gc_thresh3
+ sysctl_restore net.ipv6.neigh.default.gc_thresh2
+ sysctl_restore net.ipv6.neigh.default.gc_thresh1
+}
+
+custom_hash()
+{
+ # Test that when the hash policy is set to custom, traffic is
+ # distributed only according to the fields set in the
+ # fib_multipath_hash_fields sysctl.
+ #
+ # Each time set a different field and make sure traffic is only
+ # distributed when the field is changed in the packet stream.
+
+ sysctl_set net.ipv6.fib_multipath_hash_policy 3
+
+ custom_hash_v4
+ custom_hash_v6
+
+ sysctl_restore net.ipv6.fib_multipath_hash_policy
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+tests_run
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/unicast_extensions.sh b/tools/testing/selftests/net/unicast_extensions.sh
index dbf0421986df..66354cdd5ce4 100755
--- a/tools/testing/selftests/net/unicast_extensions.sh
+++ b/tools/testing/selftests/net/unicast_extensions.sh
@@ -189,6 +189,15 @@ segmenttest 255.255.255.1 255.255.255.254 24 "assign and ping inside 255.255.255
route_test 240.5.6.7 240.5.6.1 255.1.2.1 255.1.2.3 24 "route between 240.5.6/24 and 255.1.2/24 (is allowed)"
route_test 0.200.6.7 0.200.38.1 245.99.101.1 245.99.200.111 16 "route between 0.200/16 and 245.99/16 (is allowed)"
#
+# Test support for lowest address ending in .0
+segmenttest 5.10.15.20 5.10.15.0 24 "assign and ping lowest address (/24)"
+#
+# Test support for lowest address not ending in .0
+segmenttest 192.168.101.192 192.168.101.193 26 "assign and ping lowest address (/26)"
+#
+# Routing using lowest address as a gateway/endpoint
+route_test 192.168.42.1 192.168.42.0 9.8.7.6 9.8.7.0 24 "routing using lowest address"
+#
# ==============================================
# ==== TESTS THAT CURRENTLY EXPECT FAILURE =====
# ==============================================
@@ -202,14 +211,6 @@ segmenttest 255.255.255.1 255.255.255.255 16 "assigning 255.255.255.255 (is forb
# Currently Linux does not allow this, so this should fail too
segmenttest 127.99.4.5 127.99.4.6 16 "assign and ping inside 127/8 (is forbidden)"
#
-# Test support for lowest address
-# Currently Linux does not allow this, so this should fail too
-segmenttest 5.10.15.20 5.10.15.0 24 "assign and ping lowest address (is forbidden)"
-#
-# Routing using lowest address as a gateway/endpoint
-# Currently Linux does not allow this, so this should fail too
-route_test 192.168.42.1 192.168.42.0 9.8.7.6 9.8.7.0 24 "routing using lowest address (is forbidden)"
-#
# Test support for unicast use of class D
# Currently Linux does not allow this, so this should fail too
segmenttest 225.1.2.3 225.1.2.200 24 "assign and ping class D address (is forbidden)"